Bug 1343753 - Part 3: Use AnimationValue in ElementPropertyTransition and CSSTransition.
We also need to update the interpolation code based on ServoAnimationValue in
ElementPropertyTransition::UpdateStartValueFromReplacedTransition().
Therefore, ElementPropertyTransition can be used by both Gecko and Servo.
MozReview-Commit-ID: BrIpvRR3te8
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -5204,16 +5204,22 @@ AnimationValue::operator==(const Animati
MOZ_ASSERT(!mServo || mGecko.IsNull());
if (mServo && aOther.mServo) {
return Servo_AnimationValue_DeepEqual(mServo, aOther.mServo);
}
return !mServo && !aOther.mServo &&
mGecko == aOther.mGecko;
}
+bool
+AnimationValue::operator!=(const AnimationValue& aOther) const
+{
+ return !operator==(aOther);
+}
+
float
AnimationValue::GetOpacity() const
{
MOZ_ASSERT(!mServo != mGecko.IsNull());
return mServo ? Servo_AnimationValue_GetOpacity(mServo)
: mGecko.GetFloatValue();
}
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -574,16 +574,17 @@ struct AnimationValue
// ever be set.
// FIXME: After obsoleting StyleAnimationValue, we should remove mGecko, and
// make AnimationValue a wrapper of RawServoAnimationValue to hide these
// FFIs.
StyleAnimationValue mGecko;
RefPtr<RawServoAnimationValue> mServo;
bool operator==(const AnimationValue& aOther) const;
+ bool operator!=(const AnimationValue& aOther) const;
bool IsNull() const { return mGecko.IsNull() && !mServo; }
float GetOpacity() const;
// Returns the scale for mGecko or mServo, which are calculated with
// reference to aFrame.
gfxSize GetScaleValue(const nsIFrame* aFrame) const;
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -103,37 +103,53 @@ ElementPropertyTransition::UpdateStartVa
mReplacedTransition->mTiming,
mReplacedTransition->mPlaybackRate);
if (!computedTiming.mProgress.IsNull()) {
double valuePosition =
ComputedTimingFunction::GetPortion(mReplacedTransition->mTimingFunction,
computedTiming.mProgress.Value(),
computedTiming.mBeforeFlag);
- StyleAnimationValue startValue;
- if (StyleAnimationValue::Interpolate(mProperties[0].mProperty,
- mReplacedTransition->mFromValue,
- mReplacedTransition->mToValue,
- valuePosition, startValue)) {
- MOZ_ASSERT(mProperties.Length() == 1 &&
- mProperties[0].mSegments.Length() == 1,
- "The transition should have one property and one segment");
+
+ MOZ_ASSERT(mProperties.Length() == 1 &&
+ mProperties[0].mSegments.Length() == 1,
+ "The transition should have one property and one segment");
+ MOZ_ASSERT(mKeyframes.Length() == 2,
+ "Transitions should have exactly two animation keyframes");
+ MOZ_ASSERT(mKeyframes[0].mPropertyValues.Length() == 1,
+ "Transitions should have exactly one property in their first "
+ "frame");
+
+ const AnimationValue& replacedFrom = mReplacedTransition->mFromValue;
+ const AnimationValue& replacedTo = mReplacedTransition->mToValue;
+ AnimationValue startValue;
+ if (mDocument->IsStyledByServo()) {
+ startValue.mServo =
+ Servo_AnimationValues_Interpolate(replacedFrom.mServo,
+ replacedTo.mServo,
+ valuePosition).Consume();
+ if (startValue.mServo) {
+ mKeyframes[0].mPropertyValues[0].mServoDeclarationBlock =
+ Servo_AnimationValue_Uncompute(startValue.mServo).Consume();
+ mProperties[0].mSegments[0].mFromValue = Move(startValue);
+ }
+ } else if (StyleAnimationValue::Interpolate(mProperties[0].mProperty,
+ replacedFrom.mGecko,
+ replacedTo.mGecko,
+ valuePosition,
+ startValue.mGecko)) {
nsCSSValue cssValue;
DebugOnly<bool> uncomputeResult =
StyleAnimationValue::UncomputeValue(mProperties[0].mProperty,
- startValue,
+ startValue.mGecko,
cssValue);
- mProperties[0].mSegments[0].mFromValue.mGecko = Move(startValue);
MOZ_ASSERT(uncomputeResult, "UncomputeValue should not fail");
- MOZ_ASSERT(mKeyframes.Length() == 2,
- "Transitions should have exactly two animation keyframes");
- MOZ_ASSERT(mKeyframes[0].mPropertyValues.Length() == 1,
- "Transitions should have exactly one property in their first "
- "frame");
mKeyframes[0].mPropertyValues[0].mValue = cssValue;
+
+ mProperties[0].mSegments[0].mFromValue = Move(startValue);
}
}
mReplacedTransition.reset();
}
////////////////////////// CSSTransition ////////////////////////////
@@ -338,17 +354,17 @@ CSSTransition::Tick()
nsCSSPropertyID
CSSTransition::TransitionProperty() const
{
MOZ_ASSERT(eCSSProperty_UNKNOWN != mTransitionProperty,
"Transition property should be initialized");
return mTransitionProperty;
}
-StyleAnimationValue
+AnimationValue
CSSTransition::ToValue() const
{
MOZ_ASSERT(!mTransitionToValue.IsNull(),
"Transition ToValue should be initialized");
return mTransitionToValue;
}
bool
@@ -693,17 +709,17 @@ nsTransitionManager::UpdateTransitions(
!allTransitionProperties.HasProperty(anim->TransitionProperty())) ||
// properties whose computed values changed but for which we
// did not start a new transition (because delay and
// duration are both zero, or because the new value is not
// interpolable); a new transition would have anim->ToValue()
// matching currentValue
!ExtractNonDiscreteComputedValue(anim->TransitionProperty(),
aNewStyleContext, currentValue) ||
- currentValue != anim->ToValue()) {
+ currentValue != anim->ToValue().mGecko) {
// stop the transition
if (anim->HasCurrentEffect()) {
EffectSet* effectSet =
EffectSet::GetEffectSet(aElement,
aNewStyleContext->GetPseudoType());
if (effectSet) {
effectSet->UpdateAnimationGeneration(mPresContext);
}
@@ -806,17 +822,17 @@ nsTransitionManager::ConsiderInitiatingT
AnimationValue startValue, endValue, dummyValue;
bool haveValues =
ExtractNonDiscreteComputedValue(aProperty, aOldStyleContext,
startValue.mGecko) &&
ExtractNonDiscreteComputedValue(aProperty, aNewStyleContext,
endValue.mGecko);
- bool haveChange = startValue.mGecko != endValue.mGecko;
+ bool haveChange = startValue != endValue;
bool shouldAnimate =
haveValues &&
haveChange &&
// Check that we can interpolate between these values
// (If this is ever a performance problem, we could add a
// CanInterpolate method, but it seems fine for now.)
StyleAnimationValue::Interpolate(aProperty,
@@ -852,18 +868,17 @@ nsTransitionManager::ConsiderInitiatingT
// there's no value change), but we need to return early here rather
// than cancel the running transition because shouldAnimate is false!
//
// Likewise, if we got a style change that changed the value to the
// endpoint of our finished transition, we also don't want to start
// a new transition for the reasons described in
// https://lists.w3.org/Archives/Public/www-style/2015Jan/0444.html .
if (haveCurrentTransition && haveValues &&
- aElementTransitions->mAnimations[currentIndex]->ToValue() ==
- endValue.mGecko) {
+ aElementTransitions->mAnimations[currentIndex]->ToValue() == endValue) {
// GetAnimationRule already called RestyleForAnimation.
return;
}
if (!shouldAnimate) {
if (haveCurrentTransition) {
// We're in the middle of a transition, and just got a non-transition
// style change to something that we can't animate. This might happen
@@ -906,17 +921,17 @@ nsTransitionManager::ConsiderInitiatingT
// If the new transition reverses an existing one, we'll need to
// handle the timing differently.
// FIXME: Move mStartForReversingTest, mReversePortion to CSSTransition,
// and set the timing function on transitions as an effect-level
// easing (rather than keyframe-level easing). (Bug 1292001)
if (haveCurrentTransition &&
aElementTransitions->mAnimations[currentIndex]->HasCurrentEffect() &&
oldPT &&
- oldPT->mStartForReversingTest == endValue.mGecko) {
+ oldPT->mStartForReversingTest == endValue) {
// Compute the appropriate negative transition-delay such that right
// now we'd end up at the current position.
double valuePortion =
oldPT->CurrentValuePortion() * oldPT->mReversePortion +
(1.0 - oldPT->mReversePortion);
// A timing function with negative y1 (or y2!) might make
// valuePortion negative. In this case, we still want to apply our
// reversing logic based on relative distances, not make duration
@@ -937,33 +952,33 @@ nsTransitionManager::ConsiderInitiatingT
// function, so reduce them along with the duration, but don't
// reduce positive delays.
if (delay < 0.0f) {
delay *= valuePortion;
}
duration *= valuePortion;
- startForReversingTest.mGecko = oldPT->ToValue();
+ startForReversingTest = oldPT->ToValue();
reversePortion = valuePortion;
}
TimingParams timing =
TimingParamsFromCSSParams(duration, delay,
1.0 /* iteration count */,
dom::PlaybackDirection::Normal,
dom::FillMode::Backwards);
// aElement is non-null here, so we emplace it directly.
Maybe<OwningAnimationTarget> target;
target.emplace(aElement, aNewStyleContext->GetPseudoType());
KeyframeEffectParams effectOptions;
RefPtr<ElementPropertyTransition> pt =
new ElementPropertyTransition(aElement->OwnerDoc(), target, timing,
- startForReversingTest.mGecko, reversePortion,
+ startForReversingTest, reversePortion,
effectOptions);
pt->SetKeyframes(GetTransitionKeyframes(aProperty,
Move(startValue), Move(endValue), tf),
aNewStyleContext);
MOZ_ASSERT(mPresContext->RestyleManager()->IsGecko(),
"ServoRestyleManager should not use nsTransitionManager "
@@ -1018,18 +1033,18 @@ nsTransitionManager::ConsiderInitiatingT
const AnimationPropertySegment& segment =
oldPT->Properties()[0].mSegments[0];
pt->mReplacedTransition.emplace(
ElementPropertyTransition::ReplacedTransitionProperties({
oldPT->GetAnimation()->GetStartTime().Value(),
oldPT->GetAnimation()->PlaybackRate(),
oldPT->SpecifiedTiming(),
segment.mTimingFunction,
- segment.mFromValue.mGecko,
- segment.mToValue.mGecko
+ segment.mFromValue,
+ segment.mToValue
})
);
}
animations[currentIndex]->CancelFromStyle();
oldPT = nullptr; // Clear pointer so it doesn't dangle
animations[currentIndex] = animation;
} else {
if (!animations.AppendElement(animation)) {
@@ -1073,19 +1088,20 @@ nsTransitionManager::PruneCompletedTrans
CSSTransition* anim = animations[i];
if (anim->HasCurrentEffect()) {
continue;
}
// Since effect is a finished transition, we know it didn't
// influence style.
- StyleAnimationValue currentValue;
+ AnimationValue currentValue;
if (!ExtractNonDiscreteComputedValue(anim->TransitionProperty(),
- aNewStyleContext, currentValue) ||
+ aNewStyleContext,
+ currentValue.mGecko) ||
currentValue != anim->ToValue()) {
anim->CancelFromStyle();
animations.RemoveElementAt(i);
}
} while (i != 0);
if (collection->mAnimations.IsEmpty()) {
collection->Destroy();
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -34,17 +34,17 @@ struct StyleTransition;
namespace mozilla {
struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly
{
ElementPropertyTransition(nsIDocument* aDocument,
Maybe<OwningAnimationTarget>& aTarget,
const TimingParams &aTiming,
- StyleAnimationValue aStartForReversingTest,
+ AnimationValue aStartForReversingTest,
double aReversePortion,
const KeyframeEffectParams& aEffectOptions)
: dom::KeyframeEffectReadOnly(aDocument, aTarget, aTiming, aEffectOptions)
, mStartForReversingTest(aStartForReversingTest)
, mReversePortion(aReversePortion)
{ }
ElementPropertyTransition* AsTransition() override { return this; }
@@ -58,35 +58,35 @@ struct ElementPropertyTransition : publi
"Transitions should have exactly two animation keyframes. "
"Perhaps we are using an un-initialized transition?");
MOZ_ASSERT(mKeyframes[0].mPropertyValues.Length() == 1,
"Transitions should have exactly one property in their first "
"frame");
return mKeyframes[0].mPropertyValues[0].mProperty;
}
- StyleAnimationValue ToValue() const {
+ AnimationValue ToValue() const {
// If we failed to generate properties from the transition frames,
// return a null value but also show a warning since we should be
// detecting that kind of situation in advance and not generating a
// transition in the first place.
if (mProperties.Length() < 1 ||
mProperties[0].mSegments.Length() < 1) {
NS_WARNING("Failed to generate transition property values");
- return StyleAnimationValue();
+ return AnimationValue();
}
- return mProperties[0].mSegments[0].mToValue.mGecko;
+ return mProperties[0].mSegments[0].mToValue;
}
// This is the start value to be used for a check for whether a
// transition is being reversed. Normally the same as
// mProperties[0].mSegments[0].mFromValue, except when this transition
// started as the reversal of another in-progress transition.
// Needed so we can handle two reverses in a row.
- StyleAnimationValue mStartForReversingTest;
+ AnimationValue mStartForReversingTest;
// Likewise, the portion (in value space) of the "full" reversed
// transition that we're actually covering. For example, if a :hover
// effect has a transition that moves the element 10px to the right
// (by changing 'left' from 0px to 10px), and the mouse moves in to
// the element (starting the transition) but then moves out after the
// transition has advanced 4px, the second transition (from 10px/4px
// to 0px) will have mReversePortion of 0.4. (If the mouse then moves
// in again when the transition is back to 2px, the mReversePortion
@@ -103,17 +103,17 @@ struct ElementPropertyTransition : publi
// transitions at the current time.
void UpdateStartValueFromReplacedTransition();
struct ReplacedTransitionProperties {
TimeDuration mStartTime;
double mPlaybackRate;
TimingParams mTiming;
Maybe<ComputedTimingFunction> mTimingFunction;
- StyleAnimationValue mFromValue, mToValue;
+ AnimationValue mFromValue, mToValue;
};
Maybe<ReplacedTransitionProperties> mReplacedTransition;
};
namespace dom {
class CSSTransition final : public Animation
{
@@ -170,17 +170,17 @@ public:
mOwningElement = OwningElementRef();
}
void SetEffectFromStyle(AnimationEffectReadOnly* aEffect);
void Tick() override;
nsCSSPropertyID TransitionProperty() const;
- StyleAnimationValue ToValue() const;
+ AnimationValue ToValue() const;
bool HasLowerCompositeOrderThan(const CSSTransition& aOther) const;
EffectCompositor::CascadeLevel CascadeLevel() const override
{
return IsTiedToMarkup() ?
EffectCompositor::CascadeLevel::Transitions :
EffectCompositor::CascadeLevel::Animations;
}
@@ -270,17 +270,17 @@ protected:
bool mNeedsNewAnimationIndexWhenRun;
// Store the transition property and to-value here since we need that
// information in order to determine if there is an existing transition
// for a given style change. We can't store that information on the
// ElementPropertyTransition (effect) however since it can be replaced
// using the Web Animations API.
nsCSSPropertyID mTransitionProperty;
- StyleAnimationValue mTransitionToValue;
+ AnimationValue mTransitionToValue;
};
} // namespace dom
template <>
struct AnimationTypeTraits<dom::CSSTransition>
{
static nsIAtom* ElementPropertyAtom()