Bug 1332211 - refactor animation code in AsyncCompositionManager, r?hiro
MozReview-Commit-ID: 5PGYTv1cSeT
--- 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);
}
});