mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1078122 part 3 - Move animation value building down to the Animation objects; r=dholbert
This patch extracts the logic for calculating animation styles from AnimationPlayerCollection and puts the bulk of it into the Animation objects. Some of the initial logic surrounding the animation player state (e.g. is it paused or not, etc.) is put into AnimationPlayer. In future we may shift this logic even further down to the AnimationEffect objects but currently we don't create such objects unless necessary.
This commit is contained in:
parent
b46fbc6e51
commit
3458ab6540
@ -7,6 +7,8 @@
|
||||
#include "mozilla/dom/AnimationBinding.h"
|
||||
#include "mozilla/dom/AnimationEffect.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "AnimationCommon.h"
|
||||
#include "nsCSSPropertySet.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -262,5 +264,88 @@ Animation::HasAnimationOfProperty(nsCSSProperty aProperty) const
|
||||
return false;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -21,8 +21,12 @@
|
||||
#include "nsStyleStruct.h" // for nsTimingFunction
|
||||
|
||||
struct JSContext;
|
||||
class nsCSSPropertySet;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class AnimValuesStyleRule;
|
||||
} // namespace css
|
||||
|
||||
/**
|
||||
* Input timing parameters.
|
||||
@ -259,6 +263,13 @@ public:
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
// Updates |aStyleRule| with the animation values produced by this
|
||||
// Animation for the current time except any properties already contained
|
||||
// in |aSetProperties|.
|
||||
// Any updated properties are added to |aSetProperties|.
|
||||
void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
|
||||
nsCSSPropertySet& aSetProperties);
|
||||
|
||||
protected:
|
||||
virtual ~Animation() { }
|
||||
|
||||
|
@ -210,6 +210,22 @@ AnimationPlayer::CanThrottle() const
|
||||
return mSource->LastNotification() == Animation::LAST_NOTIFICATION_END;
|
||||
}
|
||||
|
||||
void
|
||||
AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
|
||||
nsCSSPropertySet& aSetProperties,
|
||||
bool& aNeedsRefreshes)
|
||||
{
|
||||
if (!mSource || mSource->IsFinishedTransition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (PlayState() == AnimationPlayState::Running) {
|
||||
aNeedsRefreshes = true;
|
||||
}
|
||||
|
||||
mSource->ComposeStyle(aStyleRule, aSetProperties);
|
||||
}
|
||||
|
||||
void
|
||||
AnimationPlayer::FlushStyle() const
|
||||
{
|
||||
|
@ -21,8 +21,12 @@
|
||||
#endif
|
||||
|
||||
struct JSContext;
|
||||
class nsCSSPropertySet;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class AnimValuesStyleRule;
|
||||
} // namespace css
|
||||
|
||||
class CSSAnimationPlayer;
|
||||
|
||||
@ -100,6 +104,17 @@ public:
|
||||
// running on the compositor).
|
||||
bool CanThrottle() const;
|
||||
|
||||
// Updates |aStyleRule| with the animation values of this player's source
|
||||
// content, if any.
|
||||
// Any properties already contained in |aSetProperties| are not changed. Any
|
||||
// properties that are changed are added to |aSetProperties|.
|
||||
// |aNeedsRefreshes| will be set to true if this player expects to update
|
||||
// the style rule on the next refresh driver tick as well (because it
|
||||
// is running and has source content to sample).
|
||||
void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule,
|
||||
nsCSSPropertySet& aSetProperties,
|
||||
bool& aNeedsRefreshes);
|
||||
|
||||
// The beginning of the delay period.
|
||||
Nullable<TimeDuration> mStartTime; // Timeline timescale
|
||||
|
||||
|
@ -512,108 +512,15 @@ AnimationPlayerCollection::EnsureStyleRuleFor(TimeStamp aRefreshTime,
|
||||
// We'll set mNeedsRefreshes to true below in all cases where we need them.
|
||||
mNeedsRefreshes = false;
|
||||
|
||||
// FIXME(spec): assume that properties in higher animations override
|
||||
// those in lower ones.
|
||||
// Therefore, we iterate from last animation to first.
|
||||
// If multiple animations specify behavior for the same property the
|
||||
// animation which occurs last in the value of animation-name wins.
|
||||
// As a result, we iterate from last animation to first and, if a
|
||||
// property has already been set, we don't leave it.
|
||||
nsCSSPropertySet properties;
|
||||
|
||||
for (size_t playerIdx = mPlayers.Length(); playerIdx-- != 0; ) {
|
||||
AnimationPlayer* player = mPlayers[playerIdx];
|
||||
|
||||
if (!player->GetSource() || player->GetSource()->IsFinishedTransition()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The GetComputedTiming() call here handles pausing. But:
|
||||
// FIXME: avoid recalculating every time when paused.
|
||||
ComputedTiming computedTiming = player->GetSource()->GetComputedTiming();
|
||||
|
||||
if ((computedTiming.mPhase == ComputedTiming::AnimationPhase_Before ||
|
||||
computedTiming.mPhase == ComputedTiming::AnimationPhase_Active) &&
|
||||
!player->IsPaused()) {
|
||||
mNeedsRefreshes = true;
|
||||
}
|
||||
|
||||
// If the time fraction is null, we don't have fill data for the current
|
||||
// time so we shouldn't animate.
|
||||
// Likewise, if the player has no source content.
|
||||
if (computedTiming.mTimeFraction == ComputedTiming::kNullTimeFraction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NS_ABORT_IF_FALSE(0.0 <= computedTiming.mTimeFraction &&
|
||||
computedTiming.mTimeFraction <= 1.0,
|
||||
"timing fraction should be in [0-1]");
|
||||
|
||||
const Animation* anim = player->GetSource();
|
||||
for (size_t propIdx = 0, propEnd = anim->Properties().Length();
|
||||
propIdx != propEnd; ++propIdx)
|
||||
{
|
||||
const AnimationProperty& prop = anim->Properties()[propIdx];
|
||||
|
||||
NS_ABORT_IF_FALSE(prop.mSegments[0].mFromKey == 0.0,
|
||||
"incorrect first from key");
|
||||
NS_ABORT_IF_FALSE(prop.mSegments[prop.mSegments.Length() - 1].mToKey
|
||||
== 1.0,
|
||||
"incorrect last to key");
|
||||
|
||||
if (properties.HasProperty(prop.mProperty)) {
|
||||
// A later animation already set this property.
|
||||
continue;
|
||||
}
|
||||
properties.AddProperty(prop.mProperty);
|
||||
|
||||
NS_ABORT_IF_FALSE(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) {
|
||||
NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey,
|
||||
"incorrect keys");
|
||||
++segment;
|
||||
if (segment == segmentEnd) {
|
||||
NS_ABORT_IF_FALSE(false, "incorrect time fraction");
|
||||
break; // in order to continue in outer loop (just below)
|
||||
}
|
||||
NS_ABORT_IF_FALSE(segment->mFromKey == (segment-1)->mToKey,
|
||||
"incorrect keys");
|
||||
}
|
||||
if (segment == segmentEnd) {
|
||||
continue;
|
||||
}
|
||||
NS_ABORT_IF_FALSE(segment->mFromKey < segment->mToKey,
|
||||
"incorrect keys");
|
||||
NS_ABORT_IF_FALSE(segment >= prop.mSegments.Elements() &&
|
||||
size_t(segment - prop.mSegments.Elements()) <
|
||||
prop.mSegments.Length(),
|
||||
"out of array bounds");
|
||||
|
||||
if (!mStyleRule) {
|
||||
// Allocate the style rule now that we know we have animation data.
|
||||
mStyleRule = new css::AnimValuesStyleRule();
|
||||
}
|
||||
|
||||
double positionInSegment =
|
||||
(computedTiming.mTimeFraction - segment->mFromKey) /
|
||||
(segment->mToKey - segment->mFromKey);
|
||||
double valuePosition =
|
||||
segment->mTimingFunction.GetValue(positionInSegment);
|
||||
|
||||
StyleAnimationValue *val =
|
||||
mStyleRule->AddEmptyValue(prop.mProperty);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool result =
|
||||
#endif
|
||||
StyleAnimationValue::Interpolate(prop.mProperty,
|
||||
segment->mFromValue,
|
||||
segment->mToValue,
|
||||
valuePosition, *val);
|
||||
NS_ABORT_IF_FALSE(result, "interpolate must succeed now");
|
||||
}
|
||||
mPlayers[playerIdx]->ComposeStyle(mStyleRule, properties,
|
||||
mNeedsRefreshes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ EXPORTS += [
|
||||
'nsCSSParser.h',
|
||||
'nsCSSPropAliasList.h',
|
||||
'nsCSSProperty.h',
|
||||
'nsCSSPropertySet.h',
|
||||
'nsCSSPropList.h',
|
||||
'nsCSSProps.h',
|
||||
'nsCSSPseudoClasses.h',
|
||||
|
Loading…
Reference in New Issue
Block a user