Bug 1378602 - Part2. Move animation data from layer to AnimationInfo. r=kats draft
authorEthan Lin <ethlin@mozilla.com>
Thu, 20 Jul 2017 10:59:53 +0800
changeset 612854 3cded182ba26b1d5f56166d61d025065e2904eac
parent 612853 69d27a26f5d96029b1c63f7c422e710e4ef9804c
child 612855 089a306053251d9966d89530805b760685d46baf
push id69616
push userbmo:ethlin@mozilla.com
push dateFri, 21 Jul 2017 03:57:26 +0000
reviewerskats
bugs1378602
milestone56.0a1
Bug 1378602 - Part2. Move animation data from layer to AnimationInfo. r=kats MozReview-Commit-ID: 4gv8EfPgsii
gfx/layers/AnimationInfo.cpp
gfx/layers/AnimationInfo.h
gfx/layers/ImageLayers.cpp
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
gfx/layers/composite/TextureHost.cpp
gfx/layers/mlgpu/FrameBuilder.cpp
gfx/layers/moz.build
gfx/layers/wr/WebRenderContainerLayer.cpp
gfx/layers/wr/WebRenderContainerLayer.h
layout/painting/nsDisplayList.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AnimationInfo.cpp
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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/. */
+
+#include "AnimationInfo.h"
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/AnimationHelper.h"
+
+namespace mozilla {
+namespace layers {
+
+AnimationInfo::AnimationInfo(LayerManager* aManager) :
+  mManager(aManager),
+  mCompositorAnimationsId(0),
+  mAnimationGeneration(0),
+  mMutated(false)
+{
+}
+
+AnimationInfo::~AnimationInfo()
+{
+}
+
+void
+AnimationInfo::EnsureAnimationsId()
+{
+  if (!mCompositorAnimationsId) {
+    mCompositorAnimationsId = AnimationHelper::GetNextCompositorAnimationsId();
+  }
+}
+
+Animation*
+AnimationInfo::AddAnimation()
+{
+  // Here generates a new id when the first animation is added and
+  // this id is used to represent the animations in this layer.
+  EnsureAnimationsId();
+
+  MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
+
+  Animation* anim = mAnimations.AppendElement();
+
+  mMutated = true;
+
+  return anim;
+}
+
+Animation*
+AnimationInfo::AddAnimationForNextTransaction()
+{
+  MOZ_ASSERT(mPendingAnimations,
+             "should have called ClearAnimationsForNextTransaction first");
+
+  Animation* anim = mPendingAnimations->AppendElement();
+
+  return anim;
+}
+
+void
+AnimationInfo::ClearAnimations()
+{
+  mPendingAnimations = nullptr;
+
+  if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
+    return;
+  }
+
+  if (mManager->AsWebRenderLayerManager()) {
+    mManager->AsWebRenderLayerManager()->
+      AddCompositorAnimationsIdForDiscard(mCompositorAnimationsId);
+  }
+
+  mAnimations.Clear();
+  mAnimationData.Clear();
+
+  mMutated = true;
+}
+
+void
+AnimationInfo::ClearAnimationsForNextTransaction()
+{
+  // Ensure we have a non-null mPendingAnimations to mark a future clear.
+  if (!mPendingAnimations) {
+    mPendingAnimations = new AnimationArray;
+  }
+
+  mPendingAnimations->Clear();
+}
+
+void
+AnimationInfo::SetCompositorAnimations(const CompositorAnimations& aCompositorAnimations)
+{
+  mAnimations = aCompositorAnimations.animations();
+  mCompositorAnimationsId = aCompositorAnimations.id();
+  mAnimationData.Clear();
+  AnimationHelper::SetAnimations(mAnimations,
+                                 mAnimationData,
+                                 mBaseAnimationStyle);
+}
+
+bool
+AnimationInfo::StartPendingAnimations(const TimeStamp& aReadyTime)
+{
+  bool updated = false;
+  for (size_t animIdx = 0, animEnd = mAnimations.Length();
+       animIdx < animEnd; animIdx++) {
+    Animation& anim = mAnimations[animIdx];
+
+    // If the animation is play-pending, resolve the start time.
+    // This mirrors the calculation in Animation::StartTimeFromReadyTime.
+    if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
+        !anim.originTime().IsNull() &&
+        !anim.isNotPlaying()) {
+      TimeDuration readyTime = aReadyTime - anim.originTime();
+      anim.startTime() =
+        anim.playbackRate() == 0
+        ? readyTime
+        : readyTime - anim.holdTime().MultDouble(1.0 /
+                                                 anim.playbackRate());
+      updated = true;
+    }
+  }
+  return updated;
+}
+
+void
+AnimationInfo::TransferMutatedFlagToLayer(Layer* aLayer)
+{
+  if (mMutated) {
+    aLayer->Mutated();
+    mMutated = false;
+  }
+}
+
+bool
+AnimationInfo::ApplyPendingUpdatesForThisTransaction()
+{
+  if (mPendingAnimations) {
+    mPendingAnimations->SwapElements(mAnimations);
+    mPendingAnimations = nullptr;
+    return true;
+  }
+
+  return false;
+}
+
+bool
+AnimationInfo::HasOpacityAnimation() const
+{
+  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
+    if (mAnimations[i].property() == eCSSProperty_opacity) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool
+AnimationInfo::HasTransformAnimation() const
+{
+  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
+    if (mAnimations[i].property() == eCSSProperty_transform) {
+      return true;
+    }
+  }
+  return false;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/AnimationInfo.h
@@ -0,0 +1,76 @@
+/* -*- 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 GFX_ANIMATIONINFO_H
+#define GFX_ANIMATIONINFO_H
+
+#include "mozilla/StyleAnimationValue.h"
+
+namespace mozilla {
+namespace layers {
+
+class Animation;
+class CompositorAnimations;
+class Layer;
+class LayerManager;
+struct AnimData;
+
+class AnimationInfo
+{
+  typedef InfallibleTArray<Animation> AnimationArray;
+public:
+  explicit AnimationInfo(LayerManager* aManager);
+  virtual ~AnimationInfo();
+
+  // Ensure that this AnimationInfo has a valid (non-zero) animations id. This value is
+  // unique across layers.
+  void EnsureAnimationsId();
+
+  // Call AddAnimation to add a new animation to this layer from layout code.
+  // Caller must fill in all the properties of the returned animation.
+  // A later animation overrides an earlier one.
+  Animation* AddAnimation();
+
+  // These are a parallel to AddAnimation and clearAnimations, except
+  // they add pending animations that apply only when the next
+  // transaction is begun.  (See also
+  // SetBaseTransformForNextTransaction.)
+  Animation* AddAnimationForNextTransaction();
+
+  void SetAnimationGeneration(uint64_t aCount) { mAnimationGeneration = aCount; }
+  uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
+
+  // ClearAnimations clears animations on this layer.
+  void ClearAnimations();
+  void ClearAnimationsForNextTransaction();
+  void SetCompositorAnimations(const CompositorAnimations& aCompositorAnimations);
+  bool StartPendingAnimations(const TimeStamp& aReadyTime);
+  void TransferMutatedFlagToLayer(Layer* aLayer);
+
+  uint64_t GetCompositorAnimationsId() { return mCompositorAnimationsId; }
+  StyleAnimationValue GetBaseAnimationStyle() const { return mBaseAnimationStyle; }
+  InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
+  AnimationArray& GetAnimations() { return mAnimations; }
+  bool ApplyPendingUpdatesForThisTransaction();
+  bool HasOpacityAnimation() const;
+  bool HasTransformAnimation() const;
+
+protected:
+  LayerManager* mManager;
+  AnimationArray mAnimations;
+  uint64_t mCompositorAnimationsId;
+  nsAutoPtr<AnimationArray> mPendingAnimations;
+  InfallibleTArray<AnimData> mAnimationData;
+  // If this layer is used for OMTA, then this counter is used to ensure we
+  // stay in sync with the animation manager
+  uint64_t mAnimationGeneration;
+  StyleAnimationValue mBaseAnimationStyle;
+  bool mMutated;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // GFX_ANIMATIONINFO_H
--- a/gfx/layers/ImageLayers.cpp
+++ b/gfx/layers/ImageLayers.cpp
@@ -28,17 +28,17 @@ void ImageLayer::SetContainer(ImageConta
 
 void ImageLayer::ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface)
 {
   gfx::Matrix4x4 local = GetLocalTransform();
 
   // Snap image edges to pixel boundaries
   gfxRect sourceRect(0, 0, 0, 0);
   if (mContainer) {
-    sourceRect.SizeTo(SizeDouble(mContainer->GetCurrentSize()));
+    sourceRect.SizeTo(gfx::SizeDouble(mContainer->GetCurrentSize()));
   }
   // Snap our local transform first, and snap the inherited transform as well.
   // This makes our snapping equivalent to what would happen if our content
   // was drawn into a PaintedLayer (gfxContext would snap using the local
   // transform, then we'd snap again when compositing the PaintedLayer).
   mEffectiveTransform =
       SnapTransform(local, sourceRect, nullptr) *
       SnapTransformTranslation(aTransformToSurface, nullptr);
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -24,17 +24,16 @@
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/Telemetry.h"          // for Accumulate
 #include "mozilla/ToString.h"
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Polygon.h"        // for Polygon
-#include "mozilla/layers/AnimationHelper.h"
 #include "mozilla/layers/AsyncCanvasRenderer.h"
 #include "mozilla/layers/BSPTree.h"     // for BSPTree
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
@@ -181,141 +180,53 @@ LayerManager::RemoveUserData(void* aKey)
 {
   UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
   return d;
 }
 
 //--------------------------------------------------
 // Layer
 
-Layer::Layer(LayerManager* aManager, void* aImplData) :
-  mManager(aManager),
-  mParent(nullptr),
-  mNextSibling(nullptr),
-  mPrevSibling(nullptr),
-  mImplData(aImplData),
-  mCompositorAnimationsId(0),
-  mUseTileSourceRect(false),
+Layer::Layer(LayerManager* aManager, void* aImplData)
+  : mManager(aManager)
+  , mParent(nullptr)
+  , mNextSibling(nullptr)
+  , mPrevSibling(nullptr)
+  , mImplData(aImplData)
+  , mAnimationInfo(aManager)
+  , mUseTileSourceRect(false)
 #ifdef DEBUG
-  mDebugColorIndex(0),
+  , mDebugColorIndex(0)
 #endif
-  mAnimationGeneration(0)
 {
 }
 
 Layer::~Layer()
 {
 }
 
 void
-Layer::EnsureAnimationsId()
-{
-  if (!mCompositorAnimationsId) {
-    mCompositorAnimationsId = AnimationHelper::GetNextCompositorAnimationsId();
-  }
-}
-
-Animation*
-Layer::AddAnimation()
-{
-  // Here generates a new id when the first animation is added and
-  // this id is used to represent the animations in this layer.
-  EnsureAnimationsId();
-
-  MOZ_LAYERS_LOG_IF_SHADOWABLE(
-    this, ("Layer::Mutated(%p) AddAnimation with id=%" PRIu64, this, mCompositorAnimationsId));
-
-  MOZ_ASSERT(!mPendingAnimations, "should have called ClearAnimations first");
-
-  Animation* anim = mAnimations.AppendElement();
-
-  Mutated();
-  return anim;
-}
-
-void
-Layer::ClearAnimations()
-{
-  mPendingAnimations = nullptr;
-
-  if (mAnimations.IsEmpty() && mAnimationData.IsEmpty()) {
-    return;
-  }
-
-  MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) ClearAnimations", this));
-  mAnimations.Clear();
-  mAnimationData.Clear();
-  Mutated();
-}
-
-Animation*
-Layer::AddAnimationForNextTransaction()
-{
-  MOZ_ASSERT(mPendingAnimations,
-             "should have called ClearAnimationsForNextTransaction first");
-
-  Animation* anim = mPendingAnimations->AppendElement();
-
-  return anim;
-}
-
-void
-Layer::ClearAnimationsForNextTransaction()
-{
-  // Ensure we have a non-null mPendingAnimations to mark a future clear.
-  if (!mPendingAnimations) {
-    mPendingAnimations = new AnimationArray;
-  }
-
-  mPendingAnimations->Clear();
-}
-
-void
 Layer::SetCompositorAnimations(const CompositorAnimations& aCompositorAnimations)
 {
   MOZ_LAYERS_LOG_IF_SHADOWABLE(
-    this, ("Layer::Mutated(%p) SetCompositorAnimations with id=%" PRIu64, this, mCompositorAnimationsId));
+    this, ("Layer::Mutated(%p) SetCompositorAnimations with id=%" PRIu64, this, mAnimationInfo.GetCompositorAnimationsId()));
 
-  mAnimations = aCompositorAnimations.animations();
-  mCompositorAnimationsId = aCompositorAnimations.id();
-  mAnimationData.Clear();
-  AnimationHelper::SetAnimations(mAnimations,
-                                 mAnimationData,
-                                 mBaseAnimationStyle);
+  mAnimationInfo.SetCompositorAnimations(aCompositorAnimations);
 
   Mutated();
 }
 
 void
 Layer::StartPendingAnimations(const TimeStamp& aReadyTime)
 {
   ForEachNode<ForwardIterator>(
       this,
       [&aReadyTime](Layer *layer)
       {
-        bool updated = false;
-        for (size_t animIdx = 0, animEnd = layer->mAnimations.Length();
-             animIdx < animEnd; animIdx++) {
-          Animation& anim = layer->mAnimations[animIdx];
-
-          // If the animation is play-pending, resolve the start time.
-          // This mirrors the calculation in Animation::StartTimeFromReadyTime.
-          if (anim.startTime().type() == MaybeTimeDuration::Tnull_t &&
-              !anim.originTime().IsNull() &&
-              !anim.isNotPlaying()) {
-            TimeDuration readyTime = aReadyTime - anim.originTime();
-            anim.startTime() =
-              anim.playbackRate() == 0
-              ? readyTime
-              : readyTime - anim.holdTime().MultDouble(1.0 /
-                                                       anim.playbackRate());
-            updated = true;
-          }
-        }
-        if (updated) {
+        if (layer->mAnimationInfo.StartPendingAnimations(aReadyTime)) {
           layer->Mutated();
         }
       });
 }
 
 void
 Layer::SetAsyncPanZoomController(uint32_t aIndex, AsyncPanZoomController *controller)
 {
@@ -705,49 +616,37 @@ const LayerToParentLayerMatrix4x4
 Layer::GetLocalTransformTyped()
 {
   return ViewAs<LayerToParentLayerMatrix4x4>(GetLocalTransform());
 }
 
 bool
 Layer::HasOpacityAnimation() const
 {
-  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
-    if (mAnimations[i].property() == eCSSProperty_opacity) {
-      return true;
-    }
-  }
-  return false;
+  return mAnimationInfo.HasOpacityAnimation();
 }
 
 bool
 Layer::HasTransformAnimation() const
 {
-  for (uint32_t i = 0; i < mAnimations.Length(); i++) {
-    if (mAnimations[i].property() == eCSSProperty_transform) {
-      return true;
-    }
-  }
-  return false;
+  return mAnimationInfo.HasTransformAnimation();
 }
 
 void
 Layer::ApplyPendingUpdatesForThisTransaction()
 {
   if (mPendingTransform && *mPendingTransform != mSimpleAttrs.Transform()) {
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
     mSimpleAttrs.SetTransform(*mPendingTransform);
     MutatedSimple();
   }
   mPendingTransform = nullptr;
 
-  if (mPendingAnimations) {
+  if (mAnimationInfo.ApplyPendingUpdatesForThisTransaction()) {
     MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PendingUpdatesForThisTransaction", this));
-    mPendingAnimations->SwapElements(mAnimations);
-    mPendingAnimations = nullptr;
     Mutated();
   }
 
   for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
     FrameMetrics& fm = mScrollMetadata[i].GetMetrics();
     Maybe<ScrollUpdateInfo> update = Manager()->GetPendingScrollInfoUpdate(fm.GetScrollId());
     if (update) {
       fm.UpdatePendingScrollInfo(update.value());
@@ -892,16 +791,22 @@ Layer::GetVisibleRegionRelativeToRootLay
     // positioning code.
     offset += currentLayerOffset;
   }
 
   *aLayerOffset = IntPoint(offset.x, offset.y);
   return true;
 }
 
+InfallibleTArray<AnimData>&
+Layer::GetAnimationData()
+{
+  return mAnimationInfo.GetAnimationData();
+}
+
 Maybe<ParentLayerIntRect>
 Layer::GetCombinedClipRect() const
 {
   Maybe<ParentLayerIntRect> clip = GetClipRect();
 
   clip = IntersectMaybeRects(clip, GetScrolledClipRect());
 
   for (size_t i = 0; i < mScrollMetadata.Length(); i++) {
@@ -1933,20 +1838,20 @@ Layer::PrintInfo(std::stringstream& aStr
     aStream << nsPrintfCString(" [mMaskLayer=%p]", mMaskLayer.get()).get();
   }
   for (uint32_t i = 0; i < mScrollMetadata.Length(); i++) {
     if (!mScrollMetadata[i].IsDefault()) {
       aStream << nsPrintfCString(" [metrics%d=", i).get();
       AppendToString(aStream, mScrollMetadata[i], "", "]");
     }
   }
-  if (!mAnimations.IsEmpty()) {
+  if (!mAnimationInfo.GetAnimations().IsEmpty()) {
     aStream << nsPrintfCString(" [%d animations with id=%" PRIu64 " ]",
-                               (int) mAnimations.Length(),
-                               mCompositorAnimationsId).get();
+                               (int) mAnimationInfo.GetAnimations().Length(),
+                               mAnimationInfo.GetCompositorAnimationsId()).get();
   }
 }
 
 // The static helper function sets the transform matrix into the packet
 static void
 DumpTransform(layerscope::LayersPacket::Layer::Matrix* aLayerMatrix, const Matrix4x4& aMatrix)
 {
   aLayerMatrix->set_is2d(aMatrix.Is2D());
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -28,16 +28,17 @@
 #include "mozilla/TimeStamp.h"          // for TimeStamp, TimeDuration
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "mozilla/gfx/BaseMargin.h"     // for BaseMargin
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/TiledRegion.h"    // for TiledIntRegion
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/gfx/UserData.h"       // for UserData, etc
+#include "mozilla/layers/AnimationInfo.h" // for AnimationInfo
 #include "mozilla/layers/BSPTree.h"     // for LayerPolygon
 #include "mozilla/layers/LayerAttributes.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsAutoPtr, nsRefPtr, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsCSSPropertyID.h"              // for nsCSSPropertyID
 #include "nsDebug.h"                    // for NS_ASSERTION
@@ -70,17 +71,16 @@ class GLContext;
 
 namespace gfx {
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 
 class Animation;
-class AnimationData;
 class AsyncCanvasRenderer;
 class AsyncPanZoomController;
 class BasicLayerManager;
 class ClientLayerManager;
 class HostLayerManager;
 class Layer;
 class LayerMetricsWrapper;
 class PaintedLayer;
@@ -1240,42 +1240,25 @@ public:
    */
   void SetTransformIsPerspective(bool aTransformIsPerspective)
   {
     if (mSimpleAttrs.SetTransformIsPerspective(aTransformIsPerspective)) {
       MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) TransformIsPerspective", this));
       MutatedSimple();
     }
   }
-
-  // Ensure that this layer has a valid (non-zero) animations id. This value is
-  // unique across layers.
-  void EnsureAnimationsId();
-  // Call AddAnimation to add a new animation to this layer from layout code.
-  // Caller must fill in all the properties of the returned animation.
-  // A later animation overrides an earlier one.
-  Animation* AddAnimation();
-  // ClearAnimations clears animations on this layer.
-  virtual void ClearAnimations();
   // This is only called when the layer tree is updated. Do not call this from
   // layout code.  To add an animation to this layer, use AddAnimation.
   void SetCompositorAnimations(const CompositorAnimations& aCompositorAnimations);
   // Go through all animations in this layer and its children and, for
   // any animations with a null start time, update their start time such
   // that at |aReadyTime| the animation's current time corresponds to its
   // 'initial current time' value.
   void StartPendingAnimations(const TimeStamp& aReadyTime);
 
-  // These are a parallel to AddAnimation and clearAnimations, except
-  // they add pending animations that apply only when the next
-  // transaction is begun.  (See also
-  // SetBaseTransformForNextTransaction.)
-  Animation* AddAnimationForNextTransaction();
-  void ClearAnimationsForNextTransaction();
-
   /**
    * CONSTRUCTION PHASE ONLY
    * If a layer represents a fixed position element, this data is stored on the
    * layer for use by the compositor.
    *
    *   - |aScrollId| identifies the scroll frame that this element is fixed
    *     with respect to.
    *
@@ -1442,29 +1425,28 @@ public:
    *  in this case, results will not be valid. Returns true on successful
    *  traversal.
    */
   bool GetVisibleRegionRelativeToRootLayer(nsIntRegion& aResult,
                                            nsIntPoint* aLayerOffset);
 
   // Note that all lengths in animation data are either in CSS pixels or app
   // units and must be converted to device pixels by the compositor.
-  AnimationArray& GetAnimations() { return mAnimations; }
-  uint64_t GetCompositorAnimationsId() { return mCompositorAnimationsId; }
-  InfallibleTArray<AnimData>& GetAnimationData() { return mAnimationData; }
-
-  uint64_t GetAnimationGeneration() { return mAnimationGeneration; }
-  void SetAnimationGeneration(uint64_t aCount) { mAnimationGeneration = aCount; }
+  AnimationArray& GetAnimations() { return mAnimationInfo.GetAnimations(); }
+  uint64_t GetCompositorAnimationsId() { return mAnimationInfo.GetCompositorAnimationsId(); }
+  InfallibleTArray<AnimData>& GetAnimationData();
+
+  uint64_t GetAnimationGeneration() { return mAnimationInfo.GetAnimationGeneration(); }
 
   bool HasTransformAnimation() const;
   bool HasOpacityAnimation() const;
 
   StyleAnimationValue GetBaseAnimationStyle() const
   {
-    return mBaseAnimationStyle;
+    return mAnimationInfo.GetBaseAnimationStyle();
   }
 
   /**
    * Returns the local transform for this layer: either mTransform or,
    * for shadow layers, GetShadowBaseTransform(), in either case with the
    * pre- and post-scales applied.
    */
   gfx::Matrix4x4 GetLocalTransform();
@@ -1883,16 +1865,18 @@ public:
    */
   void ClearExtraDumpInfo()
   {
 #ifdef MOZ_DUMP_PAINTING
      mExtraDumpInfo.Clear();
 #endif
   }
 
+  AnimationInfo& GetAnimationInfo() { return mAnimationInfo; }
+
 protected:
   Layer(LayerManager* aManager, void* aImplData);
 
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~Layer();
 
   /**
    * We can snap layer transforms for two reasons:
@@ -1952,39 +1936,30 @@ protected:
   LayerIntRegion mVisibleRegion;
   nsTArray<ScrollMetadata> mScrollMetadata;
   EventRegions mEventRegions;
   // A mutation of |mTransform| that we've queued to be applied at the
   // end of the next transaction (if nothing else overrides it in the
   // meantime).
   nsAutoPtr<gfx::Matrix4x4> mPendingTransform;
   gfx::Matrix4x4 mEffectiveTransform;
-  AnimationArray mAnimations;
-  uint64_t mCompositorAnimationsId;
-  // See mPendingTransform above.
-  nsAutoPtr<AnimationArray> mPendingAnimations;
-  InfallibleTArray<AnimData> mAnimationData;
+  AnimationInfo mAnimationInfo;
   Maybe<ParentLayerIntRect> mClipRect;
   gfx::IntRect mTileSourceRect;
   gfx::TiledIntRegion mInvalidRegion;
   nsTArray<RefPtr<AsyncPanZoomController> > mApzcs;
   bool mUseTileSourceRect;
 #ifdef DEBUG
   uint32_t mDebugColorIndex;
 #endif
-  // If this layer is used for OMTA, then this counter is used to ensure we
-  // stay in sync with the animation manager
-  uint64_t mAnimationGeneration;
 #ifdef MOZ_DUMP_PAINTING
   nsTArray<nsCString> mExtraDumpInfo;
 #endif
   // Store display list log.
   nsCString mDisplayListLog;
-
-  StyleAnimationValue mBaseAnimationStyle;
 };
 
 /**
  * A Layer which we can paint into. It is a conceptually
  * infinite surface, but each PaintedLayer has an associated "valid region"
  * of contents that it is currently storing, which is finite. PaintedLayer
  * implementations can store content between paints.
  *
--- a/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
+++ b/gfx/layers/apz/src/AndroidDynamicToolbarAnimator.cpp
@@ -8,17 +8,19 @@
 
 #include <cmath>
 #include "FrameMetrics.h"
 #include "gfxPrefs.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Types.h"
+#include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZThreadUtils.h"
+#include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/UiCompositorControllerMessageTypes.h"
 #include "mozilla/layers/UiCompositorControllerParent.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Move.h"
 #include "mozilla/Unused.h"
@@ -504,20 +506,20 @@ AndroidDynamicToolbarAnimator::UpdateToo
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   // if the compositor has shutdown, do not create any new rendering objects.
   if (mCompositorShutdown) {
     return;
   }
 
   if (mCompositorToolbarPixels) {
-    RefPtr<DataSourceSurface> surface = Factory::CreateWrappingDataSourceSurface(
+    RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateWrappingDataSourceSurface(
         mCompositorToolbarPixels.ref().get<uint8_t>(),
         mCompositorToolbarPixelsSize.width * 4,
-        IntSize(mCompositorToolbarPixelsSize.width, mCompositorToolbarPixelsSize.height),
+        gfx::IntSize(mCompositorToolbarPixelsSize.width, mCompositorToolbarPixelsSize.height),
         gfx::SurfaceFormat::B8G8R8A8);
 
     if (!mCompositorToolbarTexture) {
       mCompositorToolbarTexture = gl->CreateDataTextureSource();
       mCompositorToolbarEffect = nullptr;
     }
 
     if (!mCompositorToolbarTexture->Update(surface)) {
@@ -543,17 +545,17 @@ AndroidDynamicToolbarAnimator::GetToolba
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   // if the compositor has shutdown, do not create any new rendering objects.
   if (mCompositorShutdown) {
     return nullptr;
   }
 
   if (mCompositorToolbarTexture) {
     if (!mCompositorToolbarEffect) {
-      mCompositorToolbarEffect = new EffectRGB(mCompositorToolbarTexture, true, SamplingFilter::LINEAR);
+      mCompositorToolbarEffect = new EffectRGB(mCompositorToolbarTexture, true, gfx::SamplingFilter::LINEAR);
     }
 
     float ratioVisible = (float)mCompositorToolbarHeight / (float)mCompositorMaxToolbarHeight;
     mCompositorToolbarEffect->mTextureCoords.y = 1.0f - ratioVisible;
     mCompositorToolbarEffect->mTextureCoords.height = ratioVisible;
   }
 
   return mCompositorToolbarEffect.get();
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -93,17 +93,17 @@ public:
   wr::MaybeExternalImageId mExternalImageId;
 };
 
 static bool
 WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
                              LayersBackend aBackend,
                              TextureFlags aFlags)
 {
-  if (!gfxVars::UseWebRender() ||
+  if (!gfx::gfxVars::UseWebRender() ||
       (aFlags & TextureFlags::SNAPSHOT) ||
       (aBackend != LayersBackend::LAYERS_WR) ||
       (!aDeallocator->UsesImageBridge() && !aDeallocator->AsCompositorBridgeParentBase())) {
     return false;
   }
   return true;
 }
 
--- a/gfx/layers/mlgpu/FrameBuilder.cpp
+++ b/gfx/layers/mlgpu/FrameBuilder.cpp
@@ -4,16 +4,17 @@
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FrameBuilder.h"
 #include "ContainerLayerMLGPU.h"
 #include "GeckoProfiler.h"              // for profiler_*
 #include "LayerMLGPU.h"
 #include "LayerManagerMLGPU.h"
 #include "MaskOperation.h"
+#include "MLGDevice.h"                  // for MLGSwapChain
 #include "RenderPassMLGPU.h"
 #include "RenderViewMLGPU.h"
 #include "mozilla/gfx/Polygon.h"
 #include "mozilla/layers/BSPTree.h"
 #include "mozilla/layers/LayersHelpers.h"
 
 namespace mozilla {
 namespace layers {
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -87,16 +87,17 @@ EXPORTS.gfxipc += [
 ]
 
 EXPORTS.mozilla.dom += [
     'apz/util/CheckerboardReportService.h',
 ]
 
 EXPORTS.mozilla.layers += [
     'AnimationHelper.h',
+    'AnimationInfo.h',
     'apz/public/CompositorController.h',
     'apz/public/GeckoContentController.h',
     'apz/public/IAPZCTreeManager.h',
     'apz/public/MetricsSharingController.h',
     # exporting things from apz/src is temporary until we extract a
     # proper interface for the code there
     'apz/src/APZCTreeManager.h',
     'apz/src/APZUtils.h',
@@ -281,16 +282,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'andr
         'apz/src/AndroidDynamicToolbarAnimator.cpp',
     ]
     EXPORTS.mozilla.layers += [
         'apz/src/AndroidDynamicToolbarAnimator.h',
     ]
 
 UNIFIED_SOURCES += [
     'AnimationHelper.cpp',
+    'AnimationInfo.cpp',
     'apz/public/IAPZCTreeManager.cpp',
     'apz/src/APZCTreeManager.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/Axis.cpp',
     'apz/src/CheckerboardEvent.cpp',
     'apz/src/DragTracker.cpp',
     'apz/src/FocusState.cpp',
     'apz/src/FocusTarget.cpp',
--- a/gfx/layers/wr/WebRenderContainerLayer.cpp
+++ b/gfx/layers/wr/WebRenderContainerLayer.cpp
@@ -13,31 +13,19 @@
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "UnitTransforms.h"
 
 namespace mozilla {
 namespace layers {
 
 void
-WebRenderContainerLayer::ClearAnimations()
-{
-
-  if (!GetAnimations().IsEmpty()) {
-    mManager->AsWebRenderLayerManager()->
-      AddCompositorAnimationsIdForDiscard(GetCompositorAnimationsId());
-  }
-
-  Layer::ClearAnimations();
-}
-
-void
 WebRenderContainerLayer::UpdateTransformDataForAnimation()
 {
-  for (Animation& animation : mAnimations) {
+  for (Animation& animation : mAnimationInfo.GetAnimations()) {
     if (animation.property() == eCSSProperty_transform) {
       TransformData& transformData = animation.data().get_TransformData();
       transformData.inheritedXScale() = GetInheritedXScale();
       transformData.inheritedYScale() = GetInheritedYScale();
       transformData.hasPerspectiveParent() =
         GetParent() && GetParent()->GetTransformIsPerspective();
     }
   }
@@ -95,17 +83,17 @@ WebRenderContainerLayer::RenderLayer(wr:
   // ensure that there is an animations id set on it, we will use this to give
   // WebRender updated transforms for composition.
   if (WrManager()->AsyncPanZoomEnabled() &&
       GetScrollThumbData().mDirection != ScrollDirection::NONE) {
     // A scroll thumb better not have a transform animation already or we're
     // going to end up clobbering it with APZ animating it too.
     MOZ_ASSERT(transformForSC);
 
-    EnsureAnimationsId();
+    mAnimationInfo.EnsureAnimationsId();
     animationsId = GetCompositorAnimationsId();
     // We need to set the transform in the stacking context to null for it to
     // pick up and install the animation id.
     transformForSC = nullptr;
   }
 
   if (transformForSC && transform.IsIdentity()) {
     // If the transform is an identity transform, strip it out so that WR
--- a/gfx/layers/wr/WebRenderContainerLayer.h
+++ b/gfx/layers/wr/WebRenderContainerLayer.h
@@ -40,17 +40,16 @@ protected:
 
   void UpdateTransformDataForAnimation();
 
 public:
   Layer* GetLayer() override { return this; }
   void RenderLayer(wr::DisplayListBuilder& aBuilder,
                    const StackingContextHelper& aSc) override;
 
-  void ClearAnimations() override;
   virtual void ComputeEffectiveTransforms(const gfx::Matrix4x4& aTransformToSurface) override
   {
     DefaultComputeEffectiveTransforms(aTransformToSurface);
   }
 };
 
 class WebRenderRefLayer : public WebRenderLayer,
                           public RefLayer {
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -480,35 +480,34 @@ SetAnimatable(nsCSSPropertyID aProperty,
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unsupported property");
   }
 }
 
 static void
 AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
-                        dom::Animation* aAnimation, Layer* aLayer,
+                        dom::Animation* aAnimation, AnimationInfo& aAnimationInfo,
                         AnimationData& aData, bool aPending)
 {
-  MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
   MOZ_ASSERT(aAnimation->GetEffect(),
              "Should not be adding an animation without an effect");
   MOZ_ASSERT(!aAnimation->GetCurrentOrPendingStartTime().IsNull() ||
              !aAnimation->IsPlaying() ||
              (aAnimation->GetTimeline() &&
               aAnimation->GetTimeline()->TracksWallclockTime()),
              "If the animation has an unresolved start time it should either"
              " be static (so we don't need a start time) or else have a"
              " timeline capable of converting TimeStamps (so we can calculate"
              " one later");
 
   layers::Animation* animation =
     aPending ?
-    aLayer->AddAnimationForNextTransaction() :
-    aLayer->AddAnimation();
+    aAnimationInfo.AddAnimationForNextTransaction() :
+    aAnimationInfo.AddAnimation();
 
   const TimingParams& timing = aAnimation->GetEffect()->SpecifiedTiming();
 
   // If we are starting a new transition that replaces an existing transition
   // running on the compositor, it is possible that the animation on the
   // compositor will have advanced ahead of the main thread. If we use as
   // the starting point of the new transition, the current value of the
   // replaced transition as calculated on the main thread using the refresh
@@ -596,32 +595,108 @@ AddAnimationForProperty(nsIFrame* aFrame
       static_cast<uint8_t>(segment.mFromComposite);
     animSegment->endComposite() =
       static_cast<uint8_t>(segment.mToComposite);
     animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction);
   }
 }
 
 static void
-AddAnimationsForProperty(nsIFrame* aFrame, nsCSSPropertyID aProperty,
-                         nsTArray<RefPtr<dom::Animation>>& aAnimations,
-                         Layer* aLayer, AnimationData& aData,
-                         bool aPending)
-{
+AddAnimationsForProperty(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder,
+                         nsDisplayItem* aItem, nsCSSPropertyID aProperty,
+                         AnimationInfo& aAnimationInfo, bool aPending)
+{
+  if (aPending) {
+    aAnimationInfo.ClearAnimationsForNextTransaction();
+  } else {
+    aAnimationInfo.ClearAnimations();
+  }
+
+  // Update the animation generation on the layer. We need to do this before
+  // any early returns since even if we don't add any animations to the
+  // layer, we still need to mark it as up-to-date with regards to animations.
+  // Otherwise, in RestyleManager we'll notice the discrepancy between the
+  // animation generation numbers and update the layer indefinitely.
+  uint64_t animationGeneration =
+    RestyleManager::GetAnimationGenerationForFrame(aFrame);
+  aAnimationInfo.SetAnimationGeneration(animationGeneration);
+
+  EffectCompositor::ClearIsRunningOnCompositor(aFrame, aProperty);
+  nsTArray<RefPtr<dom::Animation>> compositorAnimations =
+    EffectCompositor::GetAnimationsForCompositor(aFrame, aProperty);
+  if (compositorAnimations.IsEmpty()) {
+    return;
+  }
+
+  // If the frame is not prerendered, bail out.
+  // Do this check only during layer construction; during updating the
+  // caller is required to check it appropriately.
+  if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
+    // EffectCompositor needs to know that we refused to run this animation
+    // asynchronously so that it will not throttle the main thread
+    // animation.
+    aFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), true);
+
+    // We need to schedule another refresh driver run so that EffectCompositor
+    // gets a chance to unthrottle the animation.
+    aFrame->SchedulePaint();
+    return;
+  }
+
+  AnimationData data;
+  if (aProperty == eCSSProperty_transform) {
+    // XXX Performance here isn't ideal for SVG. We'd prefer to avoid resolving
+    // the dimensions of refBox. That said, we only get here if there are CSS
+    // animations or transitions on this element, and that is likely to be a
+    // lot rarer than transforms on SVG (the frequency of which drives the need
+    // for TransformReferenceBox).
+    TransformReferenceBox refBox(aFrame);
+    nsRect bounds(0, 0, refBox.Width(), refBox.Height());
+    // all data passed directly to the compositor should be in dev pixels
+    int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
+    float scale = devPixelsToAppUnits;
+    Point3D offsetToTransformOrigin =
+      nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
+    nsPoint origin;
+    float scaleX = 1.0f;
+    float scaleY = 1.0f;
+    bool hasPerspectiveParent = false;
+    if (aItem) {
+      // This branch is for display items to leverage the cache of
+      // nsDisplayListBuilder.
+      origin = aItem->ToReferenceFrame();
+    } else {
+      // This branch is running for restyling.
+      // Animations are animated at the coordination of the reference
+      // frame outside, not the given frame itself.  The given frame
+      // is also reference frame too, so the parent's reference frame
+      // are used.
+      nsIFrame* referenceFrame =
+        nsLayoutUtils::GetReferenceFrame(nsLayoutUtils::GetCrossDocParentFrame(aFrame));
+      origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
+    }
+
+    data = TransformData(origin, offsetToTransformOrigin,
+                         bounds, devPixelsToAppUnits,
+                         scaleX, scaleY, hasPerspectiveParent);
+  } else if (aProperty == eCSSProperty_opacity) {
+    data = null_t();
+  }
+
   MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
                                       CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
              "inconsistent property flags");
 
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
   MOZ_ASSERT(effects);
 
   bool sentAnimations = false;
   // Add from first to last (since last overrides)
-  for (size_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) {
-    dom::Animation* anim = aAnimations[animIdx];
+  for (size_t animIdx = 0; animIdx < compositorAnimations.Length(); animIdx++) {
+    dom::Animation* anim = compositorAnimations[animIdx];
     if (!anim->IsRelevant()) {
       continue;
     }
 
     dom::KeyframeEffectReadOnly* keyframeEffect =
       anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
     MOZ_ASSERT(keyframeEffect,
                "A playing animation should have a keyframe effect");
@@ -653,17 +728,17 @@ AddAnimationsForProperty(nsIFrame* aFram
     // driver under test control. In this case, the next time the refresh
     // driver is advanced it will trigger any pending animations.
     if (anim->PlayState() == AnimationPlayState::Pending &&
         (anim->GetTimeline() &&
          !anim->GetTimeline()->TracksWallclockTime())) {
       continue;
     }
 
-    AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending);
+    AddAnimationForProperty(aFrame, *property, anim, aAnimationInfo, data, aPending);
     keyframeEffect->SetIsRunningOnCompositor(aProperty, true);
     sentAnimations = true;
   }
 
   if (sentAnimations && aProperty == eCSSProperty_transform) {
     TimeStamp now = aFrame->PresContext()->RefreshDriver()->MostRecentRefresh();
     effects->UpdateLastTransformSyncTime(now);
   }
@@ -772,96 +847,20 @@ nsDisplayListBuilder::AddAnimationsAndTr
   // off-main-thread compositing.
   LayersBackend backend = aLayer->Manager()->GetBackendType();
   if (!(backend == layers::LayersBackend::LAYERS_CLIENT ||
         backend == layers::LayersBackend::LAYERS_WR)) {
     return;
   }
 
   bool pending = !aBuilder;
-
-  if (pending) {
-    aLayer->ClearAnimationsForNextTransaction();
-  } else {
-    aLayer->ClearAnimations();
-  }
-
-  // Update the animation generation on the layer. We need to do this before
-  // any early returns since even if we don't add any animations to the
-  // layer, we still need to mark it as up-to-date with regards to animations.
-  // Otherwise, in RestyleManager we'll notice the discrepancy between the
-  // animation generation numbers and update the layer indefinitely.
-  uint64_t animationGeneration =
-    RestyleManager::GetAnimationGenerationForFrame(aFrame);
-  aLayer->SetAnimationGeneration(animationGeneration);
-
-  EffectCompositor::ClearIsRunningOnCompositor(aFrame, aProperty);
-  nsTArray<RefPtr<dom::Animation>> compositorAnimations =
-    EffectCompositor::GetAnimationsForCompositor(aFrame, aProperty);
-  if (compositorAnimations.IsEmpty()) {
-    return;
-  }
-
-  // If the frame is not prerendered, bail out.
-  // Do this check only during layer construction; during updating the
-  // caller is required to check it appropriately.
-  if (aItem && !aItem->CanUseAsyncAnimations(aBuilder)) {
-    // EffectCompositor needs to know that we refused to run this animation
-    // asynchronously so that it will not throttle the main thread
-    // animation.
-    aFrame->SetProperty(nsIFrame::RefusedAsyncAnimationProperty(), true);
-
-    // We need to schedule another refresh driver run so that EffectCompositor
-    // gets a chance to unthrottle the animation.
-    aFrame->SchedulePaint();
-    return;
-  }
-
-  AnimationData data;
-  if (aProperty == eCSSProperty_transform) {
-    // XXX Performance here isn't ideal for SVG. We'd prefer to avoid resolving
-    // the dimensions of refBox. That said, we only get here if there are CSS
-    // animations or transitions on this element, and that is likely to be a
-    // lot rarer than transforms on SVG (the frequency of which drives the need
-    // for TransformReferenceBox).
-    TransformReferenceBox refBox(aFrame);
-    nsRect bounds(0, 0, refBox.Width(), refBox.Height());
-    // all data passed directly to the compositor should be in dev pixels
-    int32_t devPixelsToAppUnits = aFrame->PresContext()->AppUnitsPerDevPixel();
-    float scale = devPixelsToAppUnits;
-    Point3D offsetToTransformOrigin =
-      nsDisplayTransform::GetDeltaToTransformOrigin(aFrame, scale, &bounds);
-    nsPoint origin;
-    float scaleX = 1.0f;
-    float scaleY = 1.0f;
-    bool hasPerspectiveParent = false;
-    if (aItem) {
-      // This branch is for display items to leverage the cache of
-      // nsDisplayListBuilder.
-      origin = aItem->ToReferenceFrame();
-    } else {
-      // This branch is running for restyling.
-      // Animations are animated at the coordination of the reference
-      // frame outside, not the given frame itself.  The given frame
-      // is also reference frame too, so the parent's reference frame
-      // are used.
-      nsIFrame* referenceFrame =
-        nsLayoutUtils::GetReferenceFrame(nsLayoutUtils::GetCrossDocParentFrame(aFrame));
-      origin = aFrame->GetOffsetToCrossDoc(referenceFrame);
-    }
-
-    data = TransformData(origin, offsetToTransformOrigin,
-                         bounds, devPixelsToAppUnits,
-                         scaleX, scaleY, hasPerspectiveParent);
-  } else if (aProperty == eCSSProperty_opacity) {
-    data = null_t();
-  }
-
-  AddAnimationsForProperty(aFrame, aProperty, compositorAnimations,
-                           aLayer, data, pending);
+  AnimationInfo& animationInfo = aLayer->GetAnimationInfo();
+  AddAnimationsForProperty(aFrame, aBuilder, aItem, aProperty,
+                           animationInfo, pending);
+  animationInfo.TransferMutatedFlagToLayer(aLayer);
 }
 
 void
 nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::InsertScrollFrame(nsIScrollableFrame* aScrollableFrame)
 {
   MOZ_ASSERT(!mUsed);
   size_t descendantsEndIndex = mBuilder->mActiveScrolledRoots.Length();
   const ActiveScrolledRoot* parentASR = mBuilder->mCurrentActiveScrolledRoot;