Bug 1332211 - refactor animation code in AsyncCompositionManager, r=hiro
authorpeter chang <pchang@mozilla.com>
Thu, 26 Jan 2017 15:04:16 +0800
changeset 479608 61dc0a725d0fa21b5d3472ee5741c8bd3682004f
parent 479607 4fe2c1b809e8191a6d00c86f37d98e5ca04c2d81
child 479609 8c4afac0dcbad4a3ed5694e8df0d4171a5d8c148
push id44315
push usertnguyen@mozilla.com
push dateTue, 07 Feb 2017 02:03:39 +0000
reviewershiro
bugs1332211
milestone54.0a1
Bug 1332211 - refactor animation code in AsyncCompositionManager, r=hiro MozReview-Commit-ID: 5PGYTv1cSeT
gfx/layers/AnimationHelper.cpp
gfx/layers/AnimationHelper.h
gfx/layers/composite/AsyncCompositionManager.cpp
--- a/gfx/layers/AnimationHelper.cpp
+++ b/gfx/layers/AnimationHelper.cpp
@@ -1,24 +1,201 @@
 /* -*- 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 http://mozilla.org/MPL/2.0/. */
 
 #include "AnimationHelper.h"
 #include "mozilla/ComputedTimingFunction.h" // for ComputedTimingFunction
-#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for FillMode
-#include "mozilla/layers/LayerAnimationUtils.h"  // for TimingFunctionToComputedTimingFunction
-#include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
+#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
+#include "mozilla/dom/KeyframeEffectBinding.h" // for dom::IterationComposite
+#include "mozilla/dom/KeyframeEffectReadOnly.h" // for dom::KeyFrameEffectReadOnly
+#include "mozilla/layers/LayerAnimationUtils.h" // for TimingFunctionToComputedTimingFunction
+#include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 
 namespace mozilla {
 namespace layers {
 
+struct StyleAnimationValueCompositePair {
+  StyleAnimationValue mValue;
+  dom::CompositeOperation mComposite;
+};
+
+static StyleAnimationValue
+SampleValue(float aPortion, const layers::Animation& aAnimation,
+            const StyleAnimationValueCompositePair& aStart,
+            const StyleAnimationValueCompositePair& aEnd,
+            const StyleAnimationValue& aLastValue,
+            uint64_t aCurrentIteration,
+            const StyleAnimationValue& aUnderlyingValue)
+{
+  NS_ASSERTION(aStart.mValue.IsNull() || aEnd.mValue.IsNull() ||
+               aStart.mValue.GetUnit() == aEnd.mValue.GetUnit(),
+               "Must have same unit");
+
+  StyleAnimationValue startValue =
+    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
+                                                aStart.mValue,
+                                                aUnderlyingValue,
+                                                aStart.mComposite);
+  StyleAnimationValue endValue =
+    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
+                                                aEnd.mValue,
+                                                aUnderlyingValue,
+                                                aEnd.mComposite);
+
+  // Iteration composition for accumulate
+  if (static_cast<dom::IterationCompositeOperation>
+        (aAnimation.iterationComposite()) ==
+          dom::IterationCompositeOperation::Accumulate &&
+      aCurrentIteration > 0) {
+    // FIXME: Bug 1293492: Add a utility function to calculate both of
+    // below StyleAnimationValues.
+    startValue =
+      StyleAnimationValue::Accumulate(aAnimation.property(),
+                                      aLastValue.IsNull()
+                                        ? aUnderlyingValue
+                                        : aLastValue,
+                                      Move(startValue),
+                                      aCurrentIteration);
+    endValue =
+      StyleAnimationValue::Accumulate(aAnimation.property(),
+                                      aLastValue.IsNull()
+                                        ? aUnderlyingValue
+                                        : aLastValue,
+                                      Move(endValue),
+                                      aCurrentIteration);
+  }
+
+  StyleAnimationValue interpolatedValue;
+  // This should never fail because we only pass transform and opacity values
+  // to the compositor and they should never fail to interpolate.
+  DebugOnly<bool> uncomputeResult =
+    StyleAnimationValue::Interpolate(aAnimation.property(),
+                                     startValue, endValue,
+                                     aPortion, interpolatedValue);
+  MOZ_ASSERT(uncomputeResult, "could not uncompute value");
+  return interpolatedValue;
+}
+
+bool
+AnimationHelper::SampleAnimationForEachNode(TimeStamp aPoint,
+                           AnimationArray& aAnimations,
+                           InfallibleTArray<AnimData>& aAnimationData,
+                           StyleAnimationValue& aAnimationValue,
+                           bool& aHasInEffectAnimations)
+{
+  bool activeAnimations = false;
+
+  if (aAnimations.IsEmpty()) {
+    return activeAnimations;
+  }
+
+  // Process in order, since later aAnimations override earlier ones.
+  for (size_t i = 0, iEnd = aAnimations.Length(); i < iEnd; ++i) {
+    Animation& animation = aAnimations[i];
+    AnimData& animData = aAnimationData[i];
+
+    activeAnimations = true;
+
+    MOZ_ASSERT(!animation.startTime().IsNull() ||
+               animation.isNotPlaying(),
+               "Failed to resolve start time of play-pending animations");
+    // If the animation is not currently playing , e.g. paused or
+    // finished, then use the hold time to stay at the same position.
+    TimeDuration elapsedDuration = animation.isNotPlaying()
+      ? animation.holdTime()
+      : (aPoint - animation.startTime())
+          .MultDouble(animation.playbackRate());
+    TimingParams timing;
+    timing.mDuration.emplace(animation.duration());
+    timing.mDelay = animation.delay();
+    timing.mEndDelay = animation.endDelay();
+    timing.mIterations = animation.iterations();
+    timing.mIterationStart = animation.iterationStart();
+    timing.mDirection =
+      static_cast<dom::PlaybackDirection>(animation.direction());
+    timing.mFill = static_cast<dom::FillMode>(animation.fillMode());
+    timing.mFunction =
+      AnimationUtils::TimingFunctionToComputedTimingFunction(
+        animation.easingFunction());
+
+    ComputedTiming computedTiming =
+      dom::AnimationEffectReadOnly::GetComputedTimingAt(
+        Nullable<TimeDuration>(elapsedDuration), timing,
+        animation.playbackRate());
+
+    if (computedTiming.mProgress.IsNull()) {
+      continue;
+    }
+
+    uint32_t segmentIndex = 0;
+    size_t segmentSize = animation.segments().Length();
+    AnimationSegment* segment = animation.segments().Elements();
+    while (segment->endPortion() < computedTiming.mProgress.Value() &&
+           segmentIndex < segmentSize - 1) {
+      ++segment;
+      ++segmentIndex;
+    }
+
+    double positionInSegment =
+      (computedTiming.mProgress.Value() - segment->startPortion()) /
+      (segment->endPortion() - segment->startPortion());
+
+    double portion =
+      ComputedTimingFunction::GetPortion(animData.mFunctions[segmentIndex],
+                                         positionInSegment,
+                                     computedTiming.mBeforeFlag);
+
+    StyleAnimationValueCompositePair from {
+      animData.mStartValues[segmentIndex],
+      static_cast<dom::CompositeOperation>(segment->startComposite())
+    };
+    StyleAnimationValueCompositePair to {
+      animData.mEndValues[segmentIndex],
+      static_cast<dom::CompositeOperation>(segment->endComposite())
+    };
+    // interpolate the property
+    aAnimationValue = SampleValue(portion,
+                                 animation,
+                                 from, to,
+                                 animData.mEndValues.LastElement(),
+                                 computedTiming.mCurrentIteration,
+                                 aAnimationValue);
+    aHasInEffectAnimations = true;
+  }
+
+#ifdef DEBUG
+  // Sanity check that all of animation data are the same.
+  const AnimationData& lastData = aAnimations.LastElement().data();
+  for (const Animation& animation : aAnimations) {
+    const AnimationData& data = animation.data();
+    MOZ_ASSERT(data.type() == lastData.type(),
+               "The type of AnimationData should be the same");
+    if (data.type() == AnimationData::Tnull_t) {
+      continue;
+    }
+
+    MOZ_ASSERT(data.type() == AnimationData::TTransformData);
+    const TransformData& transformData = data.get_TransformData();
+    const TransformData& lastTransformData = lastData.get_TransformData();
+    MOZ_ASSERT(transformData.origin() == lastTransformData.origin() &&
+               transformData.transformOrigin() ==
+                 lastTransformData.transformOrigin() &&
+               transformData.bounds() == lastTransformData.bounds() &&
+               transformData.appUnitsPerDevPixel() ==
+                 lastTransformData.appUnitsPerDevPixel(),
+               "All of members of TransformData should be the same");
+  }
+#endif
+  return activeAnimations;
+}
+
 static inline void
 SetCSSAngle(const CSSAngle& aAngle, nsCSSValue& aValue)
 {
   aValue.SetFloatValue(aAngle.value(), nsCSSUnit(aAngle.unit()));
 }
 
 static nsCSSValueSharedList*
 CreateCSSValueList(const InfallibleTArray<TransformFunction>& aFunctions)
--- a/gfx/layers/AnimationHelper.h
+++ b/gfx/layers/AnimationHelper.h
@@ -22,16 +22,24 @@ struct AnimData {
   InfallibleTArray<mozilla::StyleAnimationValue> mStartValues;
   InfallibleTArray<mozilla::StyleAnimationValue> mEndValues;
   InfallibleTArray<Maybe<mozilla::ComputedTimingFunction>> mFunctions;
 };
 
 class AnimationHelper
 {
 public:
+
+  static bool
+  SampleAnimationForEachNode(TimeStamp aPoint,
+                             AnimationArray& aAnimations,
+                             InfallibleTArray<AnimData>& aAnimationData,
+                             StyleAnimationValue& aAnimationValue,
+                             bool& aHasInEffectAnimations);
+
   static void
   SetAnimations(AnimationArray& aAnimations,
                 InfallibleTArray<AnimData>& aAnimData,
                 StyleAnimationValue& aBaseAnimationStyle);
 };
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -9,19 +9,16 @@
 #include "apz/src/AsyncPanZoomController.h"
 #include "FrameMetrics.h"               // for FrameMetrics
 #include "LayerManagerComposite.h"      // for LayerManagerComposite, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "gfxPoint.h"                   // for gfxPoint, gfxSize
 #include "gfxPrefs.h"                   // for gfxPrefs
 #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
 #include "mozilla/WidgetUtils.h"        // for ComputeTransformForRotation
-#include "mozilla/dom/KeyframeEffectReadOnly.h"
-#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
-#include "mozilla/dom/KeyframeEffectBinding.h" // for dom::IterationComposite
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "mozilla/gfx/Point.h"          // for RoundedToInt, PointTyped
 #include "mozilla/gfx/Rect.h"           // for RoundedToInt, RectTyped
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/layers/AnimationHelper.h"
 #include "mozilla/layers/APZUtils.h"    // for CompleteAsyncTransform
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
@@ -572,78 +569,16 @@ AsyncCompositionManager::AlignFixedAndSt
       AlignFixedAndStickyLayers(aTransformedSubtreeRoot, child, aTransformScrollId,
           aPreviousTransformForRoot, newTransform, aFixedLayerMargins, aClipPartsCache);
     }
   }
 
   return;
 }
 
-struct StyleAnimationValueCompositePair {
-  StyleAnimationValue mValue;
-  dom::CompositeOperation mComposite;
-};
-
-static StyleAnimationValue
-SampleValue(float aPortion, const Animation& aAnimation,
-            const StyleAnimationValueCompositePair& aStart,
-            const StyleAnimationValueCompositePair& aEnd,
-            const StyleAnimationValue& aLastValue,
-            uint64_t aCurrentIteration,
-            const StyleAnimationValue& aUnderlyingValue)
-{
-  NS_ASSERTION(aStart.mValue.IsNull() || aEnd.mValue.IsNull() ||
-               aStart.mValue.GetUnit() == aEnd.mValue.GetUnit(),
-               "Must have same unit");
-
-  StyleAnimationValue startValue =
-    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
-                                                aStart.mValue,
-                                                aUnderlyingValue,
-                                                aStart.mComposite);
-  StyleAnimationValue endValue =
-    dom::KeyframeEffectReadOnly::CompositeValue(aAnimation.property(),
-                                                aEnd.mValue,
-                                                aUnderlyingValue,
-                                                aEnd.mComposite);
-
-  // Iteration composition for accumulate
-  if (static_cast<dom::IterationCompositeOperation>
-        (aAnimation.iterationComposite()) ==
-          dom::IterationCompositeOperation::Accumulate &&
-      aCurrentIteration > 0) {
-    // FIXME: Bug 1293492: Add a utility function to calculate both of
-    // below StyleAnimationValues.
-    startValue =
-      StyleAnimationValue::Accumulate(aAnimation.property(),
-                                      aLastValue.IsNull()
-                                        ? aUnderlyingValue
-                                        : aLastValue,
-                                      Move(startValue),
-                                      aCurrentIteration);
-    endValue =
-      StyleAnimationValue::Accumulate(aAnimation.property(),
-                                      aLastValue.IsNull()
-                                        ? aUnderlyingValue
-                                        : aLastValue,
-                                      Move(endValue),
-                                      aCurrentIteration);
-  }
-
-  StyleAnimationValue interpolatedValue;
-  // This should never fail because we only pass transform and opacity values
-  // to the compositor and they should never fail to interpolate.
-  DebugOnly<bool> uncomputeResult =
-    StyleAnimationValue::Interpolate(aAnimation.property(),
-                                     startValue, endValue,
-                                     aPortion, interpolatedValue);
-  MOZ_ASSERT(uncomputeResult, "could not uncompute value");
-  return interpolatedValue;
-}
-
 static void
 ApplyAnimatedValue(Layer* aLayer,
                    nsCSSPropertyID aProperty,
                    const AnimationData& aAnimationData,
                    const StyleAnimationValue& aValue)
 {
   HostLayer* layerCompositor = aLayer->AsHostLayer();
   switch (aProperty) {
@@ -689,144 +624,32 @@ ApplyAnimatedValue(Layer* aLayer,
       break;
     }
     default:
       MOZ_ASSERT_UNREACHABLE("Unhandled animated property");
   }
 }
 
 static bool
-SampleAnimationForEachNode(TimeStamp aPoint,
-                           AnimationArray& aAnimations,
-                           InfallibleTArray<AnimData>& aAnimationData,
-                           StyleAnimationValue& aAnimationValue,
-                           bool& aHasInEffectAnimations)
-{
-  bool activeAnimations = false;
-
-  if (aAnimations.IsEmpty()) {
-    return activeAnimations;
-  }
-
-  // Process in order, since later aAnimations override earlier ones.
-  for (size_t i = 0, iEnd = aAnimations.Length(); i < iEnd; ++i) {
-    Animation& animation = aAnimations[i];
-    AnimData& animData = aAnimationData[i];
-
-    activeAnimations = true;
-
-    MOZ_ASSERT(!animation.startTime().IsNull() ||
-               animation.isNotPlaying(),
-               "Failed to resolve start time of play-pending animations");
-    // If the animation is not currently playing , e.g. paused or
-    // finished, then use the hold time to stay at the same position.
-    TimeDuration elapsedDuration = animation.isNotPlaying()
-      ? animation.holdTime()
-      : (aPoint - animation.startTime())
-          .MultDouble(animation.playbackRate());
-    TimingParams timing;
-    timing.mDuration.emplace(animation.duration());
-    timing.mDelay = animation.delay();
-    timing.mEndDelay = animation.endDelay();
-    timing.mIterations = animation.iterations();
-    timing.mIterationStart = animation.iterationStart();
-    timing.mDirection =
-      static_cast<dom::PlaybackDirection>(animation.direction());
-    timing.mFill = static_cast<dom::FillMode>(animation.fillMode());
-    timing.mFunction =
-      AnimationUtils::TimingFunctionToComputedTimingFunction(
-        animation.easingFunction());
-
-    ComputedTiming computedTiming =
-      dom::AnimationEffectReadOnly::GetComputedTimingAt(
-        Nullable<TimeDuration>(elapsedDuration), timing,
-        animation.playbackRate());
-
-    if (computedTiming.mProgress.IsNull()) {
-      continue;
-    }
-
-    uint32_t segmentIndex = 0;
-    size_t segmentSize = animation.segments().Length();
-    AnimationSegment* segment = animation.segments().Elements();
-    while (segment->endPortion() < computedTiming.mProgress.Value() &&
-           segmentIndex < segmentSize - 1) {
-      ++segment;
-      ++segmentIndex;
-    }
-
-    double positionInSegment =
-      (computedTiming.mProgress.Value() - segment->startPortion()) /
-      (segment->endPortion() - segment->startPortion());
-
-    double portion =
-      ComputedTimingFunction::GetPortion(animData.mFunctions[segmentIndex],
-                                         positionInSegment,
-                                     computedTiming.mBeforeFlag);
-
-    StyleAnimationValueCompositePair from {
-      animData.mStartValues[segmentIndex],
-      static_cast<dom::CompositeOperation>(segment->startComposite())
-    };
-    StyleAnimationValueCompositePair to {
-      animData.mEndValues[segmentIndex],
-      static_cast<dom::CompositeOperation>(segment->endComposite())
-    };
-    // interpolate the property
-    aAnimationValue = SampleValue(portion,
-                                 animation,
-                                 from, to,
-                                 animData.mEndValues.LastElement(),
-                                 computedTiming.mCurrentIteration,
-                                 aAnimationValue);
-    aHasInEffectAnimations = true;
-  }
-
-#ifdef DEBUG
-  // Sanity check that all of animation data are the same.
-  const AnimationData& lastData = aAnimations.LastElement().data();
-  for (const Animation& animation : aAnimations) {
-    const AnimationData& data = animation.data();
-    MOZ_ASSERT(data.type() == lastData.type(),
-               "The type of AnimationData should be the same");
-    if (data.type() == AnimationData::Tnull_t) {
-      continue;
-    }
-
-    MOZ_ASSERT(data.type() == AnimationData::TTransformData);
-    const TransformData& transformData = data.get_TransformData();
-    const TransformData& lastTransformData = lastData.get_TransformData();
-    MOZ_ASSERT(transformData.origin() == lastTransformData.origin() &&
-               transformData.transformOrigin() ==
-                 lastTransformData.transformOrigin() &&
-               transformData.bounds() == lastTransformData.bounds() &&
-               transformData.appUnitsPerDevPixel() ==
-                 lastTransformData.appUnitsPerDevPixel(),
-               "All of members of TransformData should be the same");
-  }
-#endif
-  return activeAnimations;
-}
-
-static bool
 SampleAnimations(Layer* aLayer, TimeStamp aPoint)
 {
   bool activeAnimations = false;
 
   ForEachNode<ForwardIterator>(
       aLayer,
       [&activeAnimations, &aPoint] (Layer* layer)
       {
         bool hasInEffectAnimations = false;
         StyleAnimationValue animationValue = layer->GetBaseAnimationStyle();
-        activeAnimations |= SampleAnimationForEachNode(aPoint,
-                                                       layer->GetAnimations(),
-                                                       layer->GetAnimationData(),
-                                                       animationValue,
-                                                       hasInEffectAnimations);
+        activeAnimations |=
+          AnimationHelper::SampleAnimationForEachNode(aPoint,
+                                                      layer->GetAnimations(),
+                                                      layer->GetAnimationData(),
+                                                      animationValue,
+                                                      hasInEffectAnimations);
         if (hasInEffectAnimations) {
           Animation& animation = layer->GetAnimations().LastElement();
           ApplyAnimatedValue(layer,
                              animation.property(),
                              animation.data(),
                              animationValue);
         }
       });