bool Animation::IsInEffect() const { if (IsFinishedTransition()) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction; }
bool KeyframeEffectReadonly::IsInEffect() const { if (IsFinishedTransition()) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction; }
// http://w3c.github.io/web-animations/#in-play bool KeyframeEffectReadonly::IsInPlay(const AnimationPlayer& aPlayer) const { if (IsFinishedTransition() || aPlayer.PlayState() == AnimationPlayState::Finished) { return false; } return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase_Active; }
bool Animation::IsCurrent() const { if (IsFinishedTransition()) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before || computedTiming.mPhase == ComputedTiming::AnimationPhase_Active; }
// http://w3c.github.io/web-animations/#current bool KeyframeEffectReadonly::IsCurrent(const AnimationPlayer& aPlayer) const { if (IsFinishedTransition() || aPlayer.PlayState() == AnimationPlayState::Finished) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before || computedTiming.mPhase == ComputedTiming::AnimationPhase_Active; }
bool KeyframeEffectReadOnly::HasComputedTimingChanged() const { // Typically we don't need to request a restyle if the progress hasn't // changed since the last call to ComposeStyle. The one exception is if the // iteration composite mode is 'accumulate' and the current iteration has // changed, since that will often produce a different result. ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mProgress != mProgressOnLastCompose || (mEffectOptions.mIterationComposite == IterationCompositeOperation::Accumulate && computedTiming.mCurrentIteration != mCurrentIterationOnLastCompose); }
void KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule, nsCSSPropertyIDSet& aSetProperties) { ComputedTiming computedTiming = GetComputedTiming(); mProgressOnLastCompose = computedTiming.mProgress; // If the progress is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mProgress.IsNull()) { return; } for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aSetProperties.HasProperty(prop.mProperty)) { // Animations are composed by EffectCompositor by iterating // from the last animation to first. For animations targetting the // same property, the later one wins. So if this property is already set, // we should not override it. continue; } if (!prop.mWinsInCascade) { // This isn't the winning declaration, so don't add it to style. // For transitions, this is important, because it's how we // implement the rule that CSS transitions don't run when a CSS // animation is running on the same property and element. For // animations, this is only skipping things that will otherwise be // overridden. continue; } aSetProperties.AddProperty(prop.mProperty); MOZ_ASSERT(prop.mSegments.Length() > 0, "property should not be in animations if it has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(), *segmentEnd = segment + prop.mSegments.Length(); while (segment->mToKey <= computedTiming.mProgress.Value()) { MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); if ((segment+1) == segmentEnd) { break; } ++segment; MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); MOZ_ASSERT(segment >= prop.mSegments.Elements() && size_t(segment - prop.mSegments.Elements()) < prop.mSegments.Length(), "out of array bounds"); if (!aStyleRule) { // Allocate the style rule now that we know we have animation data. aStyleRule = new AnimValuesStyleRule(); } // Special handling for zero-length segments if (segment->mToKey == segment->mFromKey) { if (computedTiming.mProgress.Value() < 0) { aStyleRule->AddValue(prop.mProperty, segment->mFromValue); } else { aStyleRule->AddValue(prop.mProperty, segment->mToValue); } continue; } double positionInSegment = (computedTiming.mProgress.Value() - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = ComputedTimingFunction::GetPortion(segment->mTimingFunction, positionInSegment, computedTiming.mBeforeFlag); MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite"); StyleAnimationValue val; if (StyleAnimationValue::Interpolate(prop.mProperty, segment->mFromValue, segment->mToValue, valuePosition, val)) { aStyleRule->AddValue(prop.mProperty, Move(val)); } else if (valuePosition < 0.5) { aStyleRule->AddValue(prop.mProperty, segment->mFromValue); } else { aStyleRule->AddValue(prop.mProperty, segment->mToValue); } } }
void KeyframeEffectReadOnly::ComposeStyle( RefPtr<AnimValuesStyleRule>& aStyleRule, const nsCSSPropertyIDSet& aPropertiesToSkip) { ComputedTiming computedTiming = GetComputedTiming(); mProgressOnLastCompose = computedTiming.mProgress; mCurrentIterationOnLastCompose = computedTiming.mCurrentIteration; // If the progress is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mProgress.IsNull()) { return; } for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aPropertiesToSkip.HasProperty(prop.mProperty)) { continue; } MOZ_ASSERT(prop.mSegments.Length() > 0, "property should not be in animations if it has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(), *segmentEnd = segment + prop.mSegments.Length(); while (segment->mToKey <= computedTiming.mProgress.Value()) { MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); if ((segment+1) == segmentEnd) { break; } ++segment; MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } MOZ_ASSERT(segment->mFromKey <= segment->mToKey, "incorrect keys"); MOZ_ASSERT(segment >= prop.mSegments.Elements() && size_t(segment - prop.mSegments.Elements()) < prop.mSegments.Length(), "out of array bounds"); if (!aStyleRule) { // Allocate the style rule now that we know we have animation data. aStyleRule = new AnimValuesStyleRule(); } StyleAnimationValue fromValue = segment->mFromValue; StyleAnimationValue toValue = segment->mToValue; // Iteration composition for accumulate if (mEffectOptions.mIterationComposite == IterationCompositeOperation::Accumulate && computedTiming.mCurrentIteration > 0) { const AnimationPropertySegment& lastSegment = prop.mSegments.LastElement(); // FIXME: Bug 1293492: Add a utility function to calculate both of // below StyleAnimationValues. DebugOnly<bool> accumulateResult = StyleAnimationValue::Accumulate(prop.mProperty, fromValue, lastSegment.mToValue, computedTiming.mCurrentIteration); // We can't check the accumulation result in case of filter property. // That's because some filter property can't accumulate, // e.g. 'contrast(2) brightness(2)' onto 'brightness(1) contrast(1)' // because of mismatch of the order. MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter, "could not accumulate value"); accumulateResult = StyleAnimationValue::Accumulate(prop.mProperty, toValue, lastSegment.mToValue, computedTiming.mCurrentIteration); MOZ_ASSERT(accumulateResult || prop.mProperty == eCSSProperty_filter, "could not accumulate value"); } // Special handling for zero-length segments if (segment->mToKey == segment->mFromKey) { if (computedTiming.mProgress.Value() < 0) { aStyleRule->AddValue(prop.mProperty, Move(fromValue)); } else { aStyleRule->AddValue(prop.mProperty, Move(toValue)); } continue; } double positionInSegment = (computedTiming.mProgress.Value() - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = ComputedTimingFunction::GetPortion(segment->mTimingFunction, positionInSegment, computedTiming.mBeforeFlag); MOZ_ASSERT(IsFinite(valuePosition), "Position value should be finite"); StyleAnimationValue val; if (StyleAnimationValue::Interpolate(prop.mProperty, fromValue, toValue, valuePosition, val)) { aStyleRule->AddValue(prop.mProperty, Move(val)); } else if (valuePosition < 0.5) { aStyleRule->AddValue(prop.mProperty, Move(fromValue)); } else { aStyleRule->AddValue(prop.mProperty, Move(toValue)); } } }
void Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, nsCSSPropertySet& aSetProperties) { ComputedTiming computedTiming = GetComputedTiming(); // If the time fraction is null, we don't have fill data for the current // time so we shouldn't animate. if (computedTiming.mTimeFraction == ComputedTiming::kNullTimeFraction) { return; } MOZ_ASSERT(0.0 <= computedTiming.mTimeFraction && computedTiming.mTimeFraction <= 1.0, "timing fraction should be in [0-1]"); for (size_t propIdx = 0, propEnd = mProperties.Length(); propIdx != propEnd; ++propIdx) { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aSetProperties.HasProperty(prop.mProperty)) { // Animations are composed by AnimationPlayerCollection by iterating // from the last animation to first. For animations targetting the // same property, the later one wins. So if this property is already set, // we should not override it. return; } aSetProperties.AddProperty(prop.mProperty); MOZ_ASSERT(prop.mSegments.Length() > 0, "property should not be in animations if it has no segments"); // FIXME: Maybe cache the current segment? const AnimationPropertySegment *segment = prop.mSegments.Elements(), *segmentEnd = segment + prop.mSegments.Length(); while (segment->mToKey < computedTiming.mTimeFraction) { MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys"); ++segment; if (segment == segmentEnd) { MOZ_ASSERT_UNREACHABLE("incorrect time fraction"); break; // in order to continue in outer loop (just below) } MOZ_ASSERT(segment->mFromKey == (segment-1)->mToKey, "incorrect keys"); } if (segment == segmentEnd) { continue; } MOZ_ASSERT(segment->mFromKey < segment->mToKey, "incorrect keys"); MOZ_ASSERT(segment >= prop.mSegments.Elements() && size_t(segment - prop.mSegments.Elements()) < prop.mSegments.Length(), "out of array bounds"); if (!aStyleRule) { // Allocate the style rule now that we know we have animation data. aStyleRule = new css::AnimValuesStyleRule(); } double positionInSegment = (computedTiming.mTimeFraction - segment->mFromKey) / (segment->mToKey - segment->mFromKey); double valuePosition = segment->mTimingFunction.GetValue(positionInSegment); StyleAnimationValue *val = aStyleRule->AddEmptyValue(prop.mProperty); #ifdef DEBUG bool result = #endif StyleAnimationValue::Interpolate(prop.mProperty, segment->mFromValue, segment->mToValue, valuePosition, *val); MOZ_ASSERT(result, "interpolate must succeed now"); } }