author Boris Chiou <>
Mon, 18 Mar 2019 18:04:46 +0000
changeset 464935 5d416b07c9b9886d7456e9e209ed93247e497af8
parent 448966 6f3709b3878117466168c40affa7bca0b60cf75b
child 464936 6c55b82deb9ba9b5924ef6bfdecdffaf9f42307a
permissions -rw-r--r--
Bug 1425837 - Part 2: Factor out the conversion from ServoAnimationValue into Matrix4x4. r=hiro Both layers and web-render use this function, so we factor it out. Depends on D22562 Differential Revision:

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 */

#ifndef mozilla_layers_AnimationHelper_h
#define mozilla_layers_AnimationHelper_h

#include "mozilla/dom/Nullable.h"
#include "mozilla/ComputedTimingFunction.h"  // for ComputedTimingFunction
#include "mozilla/layers/LayersMessages.h"   // for TransformData, etc
#include "mozilla/TimeStamp.h"               // for TimeStamp
#include "mozilla/TimingParams.h"
#include "X11UndefineNone.h"

namespace mozilla {
struct AnimationValue;
namespace layers {
class Animation;

typedef InfallibleTArray<layers::Animation> AnimationArray;

struct AnimData {
  InfallibleTArray<RefPtr<RawServoAnimationValue>> mStartValues;
  InfallibleTArray<RefPtr<RawServoAnimationValue>> mEndValues;
  InfallibleTArray<Maybe<mozilla::ComputedTimingFunction>> mFunctions;
  TimingParams mTiming;
  // These two variables correspond to the variables of the same name in
  // KeyframeEffectReadOnly and are used for the same purpose: to skip composing
  // animations whose progress has not changed.
  dom::Nullable<double> mProgressOnLastCompose;
  uint64_t mCurrentIterationOnLastCompose = 0;
  // These two variables are used for a similar optimization above but are
  // applied to the timing function in each keyframe.
  uint32_t mSegmentIndexOnLastCompose = 0;
  dom::Nullable<double> mPortionInSegmentOnLastCompose;

struct AnimationTransform {
   * This transform is calculated from sampleanimation in device pixel
   * and used by compositor.
  gfx::Matrix4x4 mTransformInDevSpace;
   * This transform is calculated from frame and used by getOMTAStyle()
   * for OMTA testing.
  gfx::Matrix4x4 mFrameTransform;
  TransformData mData;

struct AnimatedValue {

  union {
    AnimationTransform mTransform;
    float mOpacity;
    nscolor mColor;

  AnimatedValue(gfx::Matrix4x4&& aTransformInDevSpace,
                gfx::Matrix4x4&& aFrameTransform, const TransformData& aData)
      : mType(AnimatedValue::TRANSFORM), mOpacity(0.0) {
    mTransform.mTransformInDevSpace = std::move(aTransformInDevSpace);
    mTransform.mFrameTransform = std::move(aFrameTransform);
    mTransform.mData = aData;

  explicit AnimatedValue(const float& aValue)
      : mType(AnimatedValue::OPACITY), mOpacity(aValue) {}

  explicit AnimatedValue(nscolor aValue)
      : mType(AnimatedValue::COLOR), mColor(aValue) {}

  ~AnimatedValue() {}

  AnimatedValue() = delete;

// CompositorAnimationStorage stores the animations and animated values
// keyed by a CompositorAnimationsId. The "animations" are a representation of
// an entire animation over time, while the "animated values" are values sampled
// from the animations at a particular point in time.
// There is one CompositorAnimationStorage per CompositorBridgeParent (i.e.
// one per browser window), and the CompositorAnimationsId key is unique within
// a particular CompositorAnimationStorage instance.
// Each layer which has animations gets a CompositorAnimationsId key, and reuses
// that key during its lifetime. Likewise, in layers-free webrender, a display
// item that is animated (e.g. nsDisplayTransform) gets a CompositorAnimationsId
// key and reuses that key (it persists the key via the frame user-data
// mechanism).
class CompositorAnimationStorage final {
  typedef nsClassHashtable<nsUint64HashKey, AnimatedValue> AnimatedValueTable;
  typedef nsClassHashtable<nsUint64HashKey, AnimationArray> AnimationsTable;

   * Set the animation transform based on the unique id and also
   * set up |aFrameTransform| and |aData| for OMTA testing
  void SetAnimatedValue(uint64_t aId, gfx::Matrix4x4&& aTransformInDevSpace,
                        gfx::Matrix4x4&& aFrameTransform,
                        const TransformData& aData);

   * Set the animation transform in device pixel based on the unique id
  void SetAnimatedValue(uint64_t aId, gfx::Matrix4x4&& aTransformInDevSpace);

   * Set the animation opacity based on the unique id
  void SetAnimatedValue(uint64_t aId, const float& aOpacity);

   * Set the animation color based on the unique id
  void SetAnimatedValue(uint64_t aId, nscolor aColor);

   * Return the animated value if a given id can map to its animated value
  AnimatedValue* GetAnimatedValue(const uint64_t& aId) const;

  OMTAValue GetOMTAValue(const uint64_t& aId) const;

   * Return the iterator of animated value table
  AnimatedValueTable::Iterator ConstAnimatedValueTableIter() const {
    return mAnimatedValues.ConstIter();

  uint32_t AnimatedValueCount() const { return mAnimatedValues.Count(); }

   * Set the animations based on the unique id
  void SetAnimations(uint64_t aId, const AnimationArray& aAnimations);

   * Return the animations if a given id can map to its animations
  AnimationArray* GetAnimations(const uint64_t& aId) const;

   * Return the iterator of animations table
  AnimationsTable::Iterator ConstAnimationsTableIter() const {
    return mAnimations.ConstIter();

  uint32_t AnimationsCount() const { return mAnimations.Count(); }

   * Clear AnimatedValues and Animations data
  void Clear();
  void ClearById(const uint64_t& aId);


  AnimatedValueTable mAnimatedValues;
  AnimationsTable mAnimations;

 * This utility class allows reusing code between the webrender and
 * non-webrender compositor-side implementations. It provides
 * utility functions for sampling animations at particular timestamps.
class AnimationHelper {
  enum class SampleResult { None, Skipped, Sampled };

   * Sample animations based on a given time stamp for a element(layer) with
   * its animation data.
   * Generally |aPreviousFrameTimeStamp| is used for the sampling if it's
   * supplied to make the animation more in sync with other animations on the
   * main-thread.  But in the case where the animation just started at the time
   * when the animation was sent to the compositor, |aCurrentTime| is used for
   * the sampling instead to avoid flickering the animation.
   * Returns SampleResult::None if none of the animations are producing a result
   * (e.g. they are in the delay phase with no backwards fill),
   * SampleResult::Skipped if the animation output did not change since the last
   * call of this function,
   * SampleResult::Sampled if the animation output was updated.
  static SampleResult SampleAnimationForEachNode(
      TimeStamp aPreviousFrameTime, TimeStamp aCurrentFrameTime,
      AnimationArray& aAnimations, InfallibleTArray<AnimData>& aAnimationData,
      RefPtr<RawServoAnimationValue>& aAnimationValue,
      const AnimatedValue* aPreviousValue);
   * Populates AnimData stuctures into |aAnimData| and |aBaseAnimationStyle|
   * based on |aAnimations|.
  static void SetAnimations(
      AnimationArray& aAnimations, InfallibleTArray<AnimData>& aAnimData,
      RefPtr<RawServoAnimationValue>& aBaseAnimationStyle);

   * Get a unique id to represent the compositor animation between child
   * and parent side. This id will be used as a key to store animation
   * data in the CompositorAnimationStorage per compositor.
   * Each layer on the content side calls this when it gets new animation
   * data.
  static uint64_t GetNextCompositorAnimationsId();

   * Sample animation based a given time stamp |aTime| and the animation
   * data inside CompositorAnimationStorage |aStorage|. The animated values
   * after sampling will be stored in CompositorAnimationStorage as well.
   * Returns true if there is any animation.
   * Note that even if there are only in-delay phase animations (i.e. not
   * visually effective), this function returns true to ensure we composite
   * again on the next tick.
  static bool SampleAnimations(CompositorAnimationStorage* aStorage,
                               TimeStamp aPreviousFrameTime,
                               TimeStamp aCurrentFrameTime);

   * Convert an animation value into a matrix given the corresponding transform
   * parameters. |aValue| must be a transform-like value (e.g. transform,
   * translate etc.).
  static gfx::Matrix4x4 ServoAnimationValueToMatrix4x4(
      const RefPtr<RawServoAnimationValue>& aValue,
      const TransformData& aTransformData);

}  // namespace layers
}  // namespace mozilla

#endif  // mozilla_layers_AnimationHelper_h