Bug 1067769 - Part 10: Implement SetTarget(). r=birtles
MozReview-Commit-ID: GW3Ujn5cbY3
--- a/dom/animation/AnimationTarget.h
+++ b/dom/animation/AnimationTarget.h
@@ -21,16 +21,22 @@ class Element;
struct OwningAnimationTarget
{
OwningAnimationTarget(dom::Element* aElement, CSSPseudoElementType aType)
: mElement(aElement), mPseudoType(aType) { }
explicit OwningAnimationTarget(dom::Element* aElement)
: mElement(aElement) { }
+ bool operator==(const OwningAnimationTarget& aOther) const
+ {
+ return mElement == aOther.mElement &&
+ mPseudoType == aOther.mPseudoType;
+ }
+
// mElement represents the parent element of a pseudo-element, not the
// generated content element.
RefPtr<dom::Element> mElement;
CSSPseudoElementType mPseudoType = CSSPseudoElementType::NotPseudo;
};
struct NonOwningAnimationTarget
{
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -769,16 +769,24 @@ void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
for (AnimationProperty& property : mProperties) {
property.mIsRunningOnCompositor = false;
}
}
void
+KeyframeEffectReadOnly::ResetWinsInCascade()
+{
+ for (AnimationProperty& property : mProperties) {
+ property.mWinsInCascade = false;
+ }
+}
+
+void
KeyframeEffectReadOnly::UpdateTargetRegistration()
{
if (!mTarget) {
return;
}
bool isRelevant = mAnimation && mAnimation->IsRelevant();
@@ -1393,22 +1401,68 @@ KeyframeEffect::NotifySpecifiedTimingUpd
RequestRestyle(EffectCompositor::RestyleType::Layer);
}
}
void
KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
{
- // TODO: fix in next patch
+ Maybe<OwningAnimationTarget> newTarget = ConvertTarget(aTarget);
+ if (mTarget == newTarget) {
+ // Assign the same target, skip it.
+ return;
+ }
+
+ if (mTarget) {
+ UnregisterTarget();
+ ResetIsRunningOnCompositor();
+ ResetWinsInCascade();
+
+ RequestRestyle(EffectCompositor::RestyleType::Layer);
+ }
+
+ mTarget = newTarget;
+
+ if (mTarget) {
+ UpdateTargetRegistration();
+ MaybeUpdateProperties();
+
+ RequestRestyle(EffectCompositor::RestyleType::Layer);
+ }
}
KeyframeEffect::~KeyframeEffect()
{
// mTiming is cycle collected, so we have to do null check first even though
// mTiming shouldn't be null during the lifetime of KeyframeEffect.
if (mTiming) {
mTiming->Unlink();
}
}
+void
+KeyframeEffect::MaybeUpdateProperties()
+{
+ if (!mTarget) {
+ return;
+ }
+
+ nsIDocument* doc = mTarget->mElement->OwnerDoc();
+ if (!doc) {
+ return;
+ }
+
+ nsIAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count ?
+ nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType) :
+ nullptr;
+ RefPtr<nsStyleContext> styleContext =
+ nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement, pseudo,
+ doc->GetShell());
+ if (!styleContext) {
+ return;
+ }
+
+ UpdateProperties(styleContext);
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -348,16 +348,17 @@ protected:
static already_AddRefed<KeyframeEffectType>
ConstructKeyframeEffect(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const OptionsType& aOptions,
ErrorResult& aRv);
void ResetIsRunningOnCompositor();
+ void ResetWinsInCascade();
// This effect is registered with its target element so long as:
//
// (a) It has a target element, and
// (b) It is "relevant" (i.e. yet to finish but not idle, or finished but
// filling forwards)
//
// As a result, we need to make sure this gets called whenever anything
@@ -432,18 +433,29 @@ public:
Constructor(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aFrames,
const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
ErrorResult& aRv);
void NotifySpecifiedTimingUpdated();
+ // This method calls MaybeUpdateProperties which is not safe to use when
+ // we are in the middle of updating style. If we need to use this when
+ // updating style, we should pass the nsStyleContext into this method and use
+ // that to update the properties rather than calling
+ // GetStyleContextForElement.
void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
protected:
~KeyframeEffect() override;
+
+ // We need to be careful to *not* call this when we are updating the style
+ // context. That's because calling GetStyleContextForElement when we are in
+ // the process of building a style context may trigger various forms of
+ // infinite recursion.
+ void MaybeUpdateProperties();
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_KeyframeEffect_h