Bug 1260655 - Add KeyframeEffectReadOnly::SetFrames; r=heycam

Earlier in this patch series we divided keyframe processing into two stages:

  (1) Turning javascript objects into an array of Keyframe objects
  (2) Calculating AnimationProperty arrays from the Keyframe objects

This patch creates a SetFrames method so that CSS animations and
CSS transitions can skip (1) and pass the frames constructed from CSS syntax
into (2).

It also adds the following additional processing:

a. Notifying animation mutation observers when the set of frames has changed.

   This is currently performed by nsAnimationManager but ultimately we should
   encapsulate this logic inside the effect itself. Furthermore, it will be
   needed when we implement effect.setFrames() (i.e. the Javascript-facing
   wrapper for this method).

b. Preserving the mWinsInCascade and mIsRunningOnCompositor state on properties
   when updating them.

   This is currently performed by:

      bool KeyframeEffectReadOnly::UpdateProperties(
          const InfallibleTArray<AnimationProperty>& aProperties)

   which is what nsAnimationManager currently uses. We will ultimately remove
   the above method and here we are just moving this code to the new version
   of UpdateProperties.

c. Requesting a restyle when the set of AnimationProperty objects has changed.

   Again, this is currently performed by the existing UpdateProperties method
   so we are just moving it here. This behavior will also be required when
   we implement effect.setFrames() and when we call UpdateProperties from
   elsewhere in restyling code.

   This is bug 1235002 but we fix it here and leave that bug to just do further
   cleanup work (e.g. re-instating the check for an empty property set before
   requesting a restyle in NotifyAnimationTimingUpdated).

d. Marking the cascade as needing an update when the set of AnimationProperty
   objects has changed.

   This is in preparation for calling UpdateProperties from elsewhere in
   restyling (e.g. when the nsStyleContext is updated).


MozReview-Commit-ID: 2ll26lsWZTm
This commit is contained in:
Brian Birtles 2016-03-30 08:59:08 +09:00
Родитель 99a1a632e3
Коммит bdacb97d48
3 изменённых файлов: 121 добавлений и 15 удалений

Просмотреть файл

@ -457,6 +457,46 @@ KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation)
NotifyAnimationTimingUpdated(); NotifyAnimationTimingUpdated();
} }
static bool
KeyframesEqualIgnoringComputedOffsets(const nsTArray<Keyframe>& aLhs,
const nsTArray<Keyframe>& aRhs)
{
if (aLhs.Length() != aRhs.Length()) {
return false;
}
for (size_t i = 0, len = aLhs.Length(); i < len; ++i) {
const Keyframe& a = aLhs[i];
const Keyframe& b = aRhs[i];
if (a.mOffset != b.mOffset ||
a.mTimingFunction != b.mTimingFunction ||
a.mPropertyValues != b.mPropertyValues) {
return false;
}
}
return true;
}
void
KeyframeEffectReadOnly::SetFrames(nsTArray<Keyframe>&& aFrames,
nsStyleContext* aStyleContext)
{
if (KeyframesEqualIgnoringComputedOffsets(aFrames, mFrames)) {
return;
}
mFrames = Move(aFrames);
KeyframeUtils::ApplyDistributeSpacing(mFrames);
if (mAnimation && mAnimation->IsRelevant()) {
nsNodeUtils::AnimationChanged(mAnimation);
}
if (aStyleContext) {
UpdateProperties(aStyleContext);
}
}
const AnimationProperty* const AnimationProperty*
KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSProperty aProperty) const
{ {
@ -531,6 +571,64 @@ KeyframeEffectReadOnly::UpdateProperties(
return true; return true;
} }
void
KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
{
MOZ_ASSERT(aStyleContext);
nsTArray<AnimationProperty> properties;
if (mTarget) {
properties =
KeyframeUtils::GetAnimationPropertiesFromKeyframes(aStyleContext,
mTarget,
mPseudoType,
mFrames);
}
if (mProperties == properties) {
return;
}
// Preserve the state of mWinsInCascade and mIsRunningOnCompositor flags.
nsCSSPropertySet winningInCascadeProperties;
nsCSSPropertySet runningOnCompositorProperties;
for (const AnimationProperty& property : mProperties) {
if (property.mWinsInCascade) {
winningInCascadeProperties.AddProperty(property.mProperty);
}
if (property.mIsRunningOnCompositor) {
runningOnCompositorProperties.AddProperty(property.mProperty);
}
}
mProperties = Move(properties);
for (AnimationProperty& property : mProperties) {
property.mWinsInCascade =
winningInCascadeProperties.HasProperty(property.mProperty);
property.mIsRunningOnCompositor =
runningOnCompositorProperties.HasProperty(property.mProperty);
}
if (mTarget) {
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget, mPseudoType);
if (effectSet) {
effectSet->MarkCascadeNeedsUpdate();
}
}
if (mAnimation) {
nsPresContext* presContext = GetPresContext();
if (presContext) {
presContext->EffectCompositor()->
RequestRestyle(mTarget, mPseudoType,
EffectCompositor::RestyleType::Layer,
mAnimation->CascadeLevel());
}
}
}
void void
KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule, KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties) nsCSSPropertySet& aSetProperties)
@ -721,7 +819,10 @@ KeyframeEffectReadOnly::ConstructKeyframeEffect(
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
KeyframeUtils::ApplyDistributeSpacing(keyframes);
RefPtr<KeyframeEffectType> effect =
new KeyframeEffectType(targetElement->OwnerDoc(), targetElement,
pseudoType, timingParams);
RefPtr<nsStyleContext> styleContext; RefPtr<nsStyleContext> styleContext;
nsIPresShell* shell = doc->GetShell(); nsIPresShell* shell = doc->GetShell();
@ -733,20 +834,8 @@ KeyframeEffectReadOnly::ConstructKeyframeEffect(
nsComputedDOMStyle::GetStyleContextForElement(targetElement, pseudo, nsComputedDOMStyle::GetStyleContextForElement(targetElement, pseudo,
shell); shell);
} }
effect->SetFrames(Move(keyframes), styleContext);
nsTArray<AnimationProperty> animationProperties;
if (styleContext) {
animationProperties =
KeyframeUtils::GetAnimationPropertiesFromKeyframes(styleContext,
targetElement,
pseudoType,
keyframes);
}
RefPtr<KeyframeEffectType> effect =
new KeyframeEffectType(targetElement->OwnerDoc(), targetElement,
pseudoType, timingParams);
effect->mProperties = Move(animationProperties);
return effect.forget(); return effect.forget();
} }

Просмотреть файл

@ -63,6 +63,11 @@ struct PropertyValuePair
// property values, we store the specified property value as a token stream // property values, we store the specified property value as a token stream
// (string). // (string).
nsCSSValue mValue; nsCSSValue mValue;
bool operator==(const PropertyValuePair& aOther) const {
return mProperty == aOther.mProperty &&
mValue == aOther.mValue;
}
}; };
/** /**
@ -274,6 +279,7 @@ public:
void SetAnimation(Animation* aAnimation); void SetAnimation(Animation* aAnimation);
Animation* GetAnimation() const { return mAnimation; } Animation* GetAnimation() const { return mAnimation; }
void SetFrames(nsTArray<Keyframe>&& aFrames, nsStyleContext* aStyleContext);
const AnimationProperty* const AnimationProperty*
GetAnimationOfProperty(nsCSSProperty aProperty) const; GetAnimationOfProperty(nsCSSProperty aProperty) const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const { bool HasAnimationOfProperty(nsCSSProperty aProperty) const {
@ -294,6 +300,10 @@ public:
bool UpdateProperties( bool UpdateProperties(
const InfallibleTArray<AnimationProperty>& aProperties); const InfallibleTArray<AnimationProperty>& aProperties);
// Update |mProperties| by recalculating from |mFrames| using |aStyleContext|
// to resolve specified values.
void UpdateProperties(nsStyleContext* aStyleContext);
// Updates |aStyleRule| with the animation values produced by this // Updates |aStyleRule| with the animation values produced by this
// AnimationEffect for the current time except any properties already // AnimationEffect for the current time except any properties already
// contained in |aSetProperties|. // contained in |aSetProperties|.
@ -363,7 +373,11 @@ protected:
OwningNonNull<AnimationEffectTimingReadOnly> mTiming; OwningNonNull<AnimationEffectTimingReadOnly> mTiming;
CSSPseudoElementType mPseudoType; CSSPseudoElementType mPseudoType;
InfallibleTArray<AnimationProperty> mProperties; // The specified keyframes.
nsTArray<Keyframe> mFrames;
// A set of per-property value arrays, derived from |mFrames|.
nsTArray<AnimationProperty> mProperties;
// The computed progress last time we composed the style rule. This is // The computed progress last time we composed the style rule. This is
// used to detect when the progress is not changing (e.g. due to a step // used to detect when the progress is not changing (e.g. due to a step

Просмотреть файл

@ -467,6 +467,9 @@ KeyframeUtils::GetAnimationPropertiesFromKeyframes(
CSSPseudoElementType aPseudoType, CSSPseudoElementType aPseudoType,
const nsTArray<Keyframe>& aFrames) const nsTArray<Keyframe>& aFrames)
{ {
MOZ_ASSERT(aStyleContext);
MOZ_ASSERT(aElement);
nsTArray<KeyframeValueEntry> entries; nsTArray<KeyframeValueEntry> entries;
for (const Keyframe& frame : aFrames) { for (const Keyframe& frame : aFrames) {