--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -5,25 +5,25 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_Animation_h
#define mozilla_dom_Animation_h
#include "nsWrapperCache.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Attributes.h"
+#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration
#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState
-#include "mozilla/dom/AnimationTimeline.h" // for AnimationTimeline
-#include "mozilla/DOMEventTargetHelper.h" // for DOMEventTargetHelper
-#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadOnly
-#include "mozilla/dom/Promise.h" // for Promise
-#include "nsCSSPropertyID.h" // for nsCSSPropertyID
+#include "mozilla/dom/AnimationEffectReadOnly.h"
+#include "mozilla/dom/AnimationTimeline.h"
+#include "mozilla/dom/Promise.h"
+#include "nsCSSPropertyID.h"
#include "nsIGlobalObject.h"
// X11 has a #define for CurrentTime.
#ifdef CurrentTime
#undef CurrentTime
#endif
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
--- a/dom/animation/AnimationEffectTiming.cpp
+++ b/dom/animation/AnimationEffectTiming.cpp
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/AnimationEffectTiming.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/AnimationEffectTimingBinding.h"
+#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/TimingParams.h"
#include "nsAString.h"
namespace mozilla {
namespace dom {
JSObject*
AnimationEffectTiming::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/animation/AnimationEffectTiming.h
+++ b/dom/animation/AnimationEffectTiming.h
@@ -9,16 +9,18 @@
#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
#include "nsStringFwd.h"
namespace mozilla {
namespace dom {
+class KeyframeEffect;
+
class AnimationEffectTiming : public AnimationEffectTimingReadOnly
{
public:
AnimationEffectTiming(nsIDocument* aDocument,
const TimingParams& aTiming,
KeyframeEffect* aEffect)
: AnimationEffectTimingReadOnly(aDocument, aTiming)
, mEffect(aEffect) { }
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -3,17 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EffectCompositor.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/Element.h"
-#include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/EffectSet.h"
#include "mozilla/InitializerList.h"
#include "mozilla/LayerAnimationInfo.h"
#include "mozilla/RestyleManagerHandle.h"
#include "mozilla/RestyleManagerHandleInlines.h"
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -7,26 +7,26 @@
#ifndef mozilla_EffectSet_h
#define mozilla_EffectSet_h
#include "mozilla/AnimValuesStyleRule.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/TimeStamp.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsHashKeys.h" // For nsPtrHashKey
#include "nsTHashtable.h" // For nsTHashtable
class nsPresContext;
namespace mozilla {
namespace dom {
class Element;
-class KeyframeEffectReadOnly;
} // namespace dom
enum class CSSPseudoElementType : uint8_t;
// A wrapper around a hashset of AnimationEffect objects to handle
// storing the set as a property of an element.
class EffectSet
{
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -2,1295 +2,25 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/AnimatableBinding.h"
+ // For UnrestrictedDoubleOrKeyframeAnimationOptions
#include "mozilla/dom/AnimationEffectTiming.h"
-#include "mozilla/dom/CSSPseudoElement.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
-#include "mozilla/AnimationUtils.h"
-#include "mozilla/EffectSet.h"
-#include "mozilla/FloatingPoint.h"
-#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
#include "mozilla/KeyframeUtils.h"
-#include "mozilla/StyleAnimationValue.h"
-#include "Layers.h" // For Layer
-#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
-#include "nsContentUtils.h" // nsContentUtils::ReportToConsole
-#include "nsCSSPropertyIDSet.h"
-#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
-#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
-#include "nsIPresShell.h" // For nsIPresShell
-#include "nsIScriptError.h"
namespace mozilla {
namespace dom {
-NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly,
- AnimationEffectReadOnly,
- mTarget)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly,
- AnimationEffectReadOnly)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly)
-NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadOnly)
-
-NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
-NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
-
-KeyframeEffectReadOnly::KeyframeEffectReadOnly(
- nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- const TimingParams& aTiming,
- const KeyframeEffectParams& aOptions)
- : KeyframeEffectReadOnly(aDocument, aTarget,
- new AnimationEffectTimingReadOnly(aDocument,
- aTiming),
- aOptions)
-{
-}
-
-KeyframeEffectReadOnly::KeyframeEffectReadOnly(
- nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- AnimationEffectTimingReadOnly* aTiming,
- const KeyframeEffectParams& aOptions)
- : AnimationEffectReadOnly(aDocument, aTiming)
- , mTarget(aTarget)
- , mEffectOptions(aOptions)
- , mInEffectOnLastAnimationTimingUpdate(false)
- , mCumulativeChangeHint(nsChangeHint(0))
-{
-}
-
-JSObject*
-KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto);
-}
-
-IterationCompositeOperation
-KeyframeEffectReadOnly::IterationComposite() const
-{
- return IterationCompositeOperation::Replace;
-}
-
-CompositeOperation
-KeyframeEffectReadOnly::Composite() const
-{
- return CompositeOperation::Replace;
-}
-
-void
-KeyframeEffectReadOnly::NotifyAnimationTimingUpdated()
-{
- UpdateTargetRegistration();
-
- // If the effect is not relevant it will be removed from the target
- // element's effect set. However, effects not in the effect set
- // will not be included in the set of candidate effects for running on
- // the compositor and hence they won't have their compositor status
- // updated. As a result, we need to make sure we clear their compositor
- // status here.
- bool isRelevant = mAnimation && mAnimation->IsRelevant();
- if (!isRelevant) {
- ResetIsRunningOnCompositor();
- }
-
- // Detect changes to "in effect" status since we need to recalculate the
- // animation cascade for this element whenever that changes.
- bool inEffect = IsInEffect();
- if (inEffect != mInEffectOnLastAnimationTimingUpdate) {
- MarkCascadeNeedsUpdate();
- mInEffectOnLastAnimationTimingUpdate = inEffect;
- }
-
- // Request restyle if necessary.
- //
- // Bug 1216843: When we implement iteration composite modes, we need to
- // also detect if the current iteration has changed.
- if (mAnimation &&
- !mProperties.IsEmpty() &&
- GetComputedTiming().mProgress != mProgressOnLastCompose) {
- EffectCompositor::RestyleType restyleType =
- CanThrottle() ?
- EffectCompositor::RestyleType::Throttled :
- EffectCompositor::RestyleType::Standard;
- RequestRestyle(restyleType);
- }
-
- // If we're no longer "in effect", our ComposeStyle method will never be
- // called and we will never have a chance to update mProgressOnLastCompose.
- // We clear mProgressOnLastCompose here to ensure that if we later become
- // "in effect" we will request a restyle (above).
- if (!inEffect) {
- mProgressOnLastCompose.SetNull();
- }
-}
-
-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;
-}
-
-// https://w3c.github.io/web-animations/#dom-keyframeeffect-setkeyframes
-void
-KeyframeEffectReadOnly::SetKeyframes(JSContext* aContext,
- JS::Handle<JSObject*> aKeyframes,
- ErrorResult& aRv)
-{
- nsTArray<Keyframe> keyframes =
- KeyframeUtils::GetKeyframesFromObject(aContext, mDocument, aKeyframes, aRv);
- if (aRv.Failed()) {
- return;
- }
-
- RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
- SetKeyframes(Move(keyframes), styleContext);
-}
-
-void
-KeyframeEffectReadOnly::SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
- nsStyleContext* aStyleContext)
-{
- if (KeyframesEqualIgnoringComputedOffsets(aKeyframes, mKeyframes)) {
- return;
- }
-
- mKeyframes = Move(aKeyframes);
- // Apply distribute spacing irrespective of the spacing mode. We will apply
- // the specified spacing mode when we generate computed animation property
- // values from the keyframes since both operations require a style context
- // and need to be performed whenever the style context changes.
- KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
-
- if (mAnimation && mAnimation->IsRelevant()) {
- nsNodeUtils::AnimationChanged(mAnimation);
- }
-
- if (aStyleContext) {
- UpdateProperties(aStyleContext);
- MaybeUpdateFrameForCompositor();
- }
-}
-
-const AnimationProperty*
-KeyframeEffectReadOnly::GetAnimationOfProperty(nsCSSPropertyID aProperty) const
-{
- for (size_t propIdx = 0, propEnd = mProperties.Length();
- propIdx != propEnd; ++propIdx) {
- if (aProperty == mProperties[propIdx].mProperty) {
- const AnimationProperty* result = &mProperties[propIdx];
- if (!result->mWinsInCascade) {
- result = nullptr;
- }
- return result;
- }
- }
- return nullptr;
-}
-
-#ifdef DEBUG
-bool
-SpecifiedKeyframeArraysAreEqual(const nsTArray<Keyframe>& aA,
- const nsTArray<Keyframe>& aB)
-{
- if (aA.Length() != aB.Length()) {
- return false;
- }
-
- for (size_t i = 0; i < aA.Length(); i++) {
- const Keyframe& a = aA[i];
- const Keyframe& b = aB[i];
- if (a.mOffset != b.mOffset ||
- a.mTimingFunction != b.mTimingFunction ||
- a.mPropertyValues != b.mPropertyValues) {
- return false;
- }
- }
-
- return true;
-}
-#endif
-
-void
-KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext)
-{
- MOZ_ASSERT(aStyleContext);
-
- nsTArray<AnimationProperty> properties;
- if (mTarget) {
- // When GetComputedKeyframeValues or GetAnimationPropertiesFromKeyframes
- // calculate computed values from |mKeyframes|, they could possibly
- // trigger a subsequent restyle in which we rebuild animations. If that
- // happens we could find that |mKeyframes| is overwritten while it is
- // being iterated over. Normally that shouldn't happen but just in case we
- // make a copy of |mKeyframes| first and iterate over that instead.
- auto keyframesCopy(mKeyframes);
-
- nsTArray<ComputedKeyframeValues> computedValues =
- KeyframeUtils::GetComputedKeyframeValues(keyframesCopy,
- mTarget->mElement,
- aStyleContext);
-
- if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
- KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
- mEffectOptions.mPacedProperty,
- computedValues);
- }
-
- properties =
- KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy,
- computedValues,
- aStyleContext);
-
-#ifdef DEBUG
- MOZ_ASSERT(SpecifiedKeyframeArraysAreEqual(mKeyframes, keyframesCopy),
- "Apart from the computed offset members, the keyframes array"
- " should not be modified");
-#endif
-
- mKeyframes.SwapElements(keyframesCopy);
- }
-
- if (mProperties == properties) {
- return;
- }
-
- // Preserve the state of mWinsInCascade and mIsRunningOnCompositor flags.
- nsCSSPropertyIDSet winningInCascadeProperties;
- nsCSSPropertyIDSet 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);
- }
-
- CalculateCumulativeChangeHint(aStyleContext);
-
- MarkCascadeNeedsUpdate();
-
- RequestRestyle(EffectCompositor::RestyleType::Layer);
-}
-
-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);
- }
- }
-}
-
-bool
-KeyframeEffectReadOnly::IsRunningOnCompositor() const
-{
- // We consider animation is running on compositor if there is at least
- // one property running on compositor.
- // Animation.IsRunningOnCompotitor will return more fine grained
- // information in bug 1196114.
- for (const AnimationProperty& property : mProperties) {
- if (property.mIsRunningOnCompositor) {
- return true;
- }
- }
- return false;
-}
-
-void
-KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSPropertyID aProperty,
- bool aIsRunning)
-{
- MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
- CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
- "Property being animated on compositor is a recognized "
- "compositor-animatable property");
- for (AnimationProperty& property : mProperties) {
- if (property.mProperty == aProperty) {
- property.mIsRunningOnCompositor = aIsRunning;
- // We currently only set a performance warning message when animations
- // cannot be run on the compositor, so if this animation is running
- // on the compositor we don't need a message.
- if (aIsRunning) {
- property.mPerformanceWarning.reset();
- }
- return;
- }
- }
-}
-
-void
-KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
-{
- for (AnimationProperty& property : mProperties) {
- property.mIsRunningOnCompositor = false;
- }
-}
-
-static const KeyframeEffectOptions&
-KeyframeEffectOptionsFromUnion(
- const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
-{
- MOZ_ASSERT(aOptions.IsKeyframeEffectOptions());
- return aOptions.GetAsKeyframeEffectOptions();
-}
-
-static const KeyframeEffectOptions&
-KeyframeEffectOptionsFromUnion(
- const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions)
-{
- MOZ_ASSERT(aOptions.IsKeyframeAnimationOptions());
- return aOptions.GetAsKeyframeAnimationOptions();
-}
-
-template <class OptionsType>
-static KeyframeEffectParams
-KeyframeEffectParamsFromUnion(const OptionsType& aOptions,
- nsAString& aInvalidPacedProperty,
- ErrorResult& aRv)
-{
- KeyframeEffectParams result;
- if (!aOptions.IsUnrestrictedDouble()) {
- const KeyframeEffectOptions& options =
- KeyframeEffectOptionsFromUnion(aOptions);
- KeyframeEffectParams::ParseSpacing(options.mSpacing,
- result.mSpacingMode,
- result.mPacedProperty,
- aInvalidPacedProperty,
- aRv);
- }
- return result;
-}
-
-static Maybe<OwningAnimationTarget>
-ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
-{
- // Return value optimization.
- Maybe<OwningAnimationTarget> result;
-
- if (aTarget.IsNull()) {
- return result;
- }
-
- const ElementOrCSSPseudoElement& target = aTarget.Value();
- MOZ_ASSERT(target.IsElement() || target.IsCSSPseudoElement(),
- "Uninitialized target");
-
- if (target.IsElement()) {
- result.emplace(&target.GetAsElement());
- } else {
- RefPtr<Element> elem = target.GetAsCSSPseudoElement().ParentElement();
- result.emplace(elem, target.GetAsCSSPseudoElement().GetType());
- }
- return result;
-}
-
-template <class KeyframeEffectType, class OptionsType>
-/* static */ already_AddRefed<KeyframeEffectType>
-KeyframeEffectReadOnly::ConstructKeyframeEffect(
- const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const OptionsType& aOptions,
- ErrorResult& aRv)
-{
- nsIDocument* doc = AnimationUtils::GetCurrentRealmDocument(aGlobal.Context());
- if (!doc) {
- aRv.Throw(NS_ERROR_FAILURE);
- return nullptr;
- }
-
- TimingParams timingParams =
- TimingParams::FromOptionsUnion(aOptions, doc, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- nsAutoString invalidPacedProperty;
- KeyframeEffectParams effectOptions =
- KeyframeEffectParamsFromUnion(aOptions, invalidPacedProperty, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- if (!invalidPacedProperty.IsEmpty()) {
- const char16_t* params[] = { invalidPacedProperty.get() };
- nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("Animation"),
- doc,
- nsContentUtils::eDOM_PROPERTIES,
- "UnanimatablePacedProperty",
- params, ArrayLength(params));
- }
-
- Maybe<OwningAnimationTarget> target = ConvertTarget(aTarget);
- RefPtr<KeyframeEffectType> effect =
- new KeyframeEffectType(doc, target, timingParams, effectOptions);
-
- effect->SetKeyframes(aGlobal.Context(), aKeyframes, aRv);
- if (aRv.Failed()) {
- return nullptr;
- }
-
- return effect.forget();
-}
-
-void
-KeyframeEffectReadOnly::UpdateTargetRegistration()
-{
- if (!mTarget) {
- return;
- }
-
- bool isRelevant = mAnimation && mAnimation->IsRelevant();
-
- // Animation::IsRelevant() returns a cached value. It only updates when
- // something calls Animation::UpdateRelevance. Whenever our timing changes,
- // we should be notifying our Animation before calling this, so
- // Animation::IsRelevant() should be up-to-date by the time we get here.
- MOZ_ASSERT(isRelevant == IsCurrent() || IsInEffect(),
- "Out of date Animation::IsRelevant value");
-
- if (isRelevant) {
- EffectSet* effectSet =
- EffectSet::GetOrCreateEffectSet(mTarget->mElement, mTarget->mPseudoType);
- effectSet->AddEffect(*this);
- } else {
- UnregisterTarget();
- }
-}
-
-void
-KeyframeEffectReadOnly::UnregisterTarget()
-{
- EffectSet* effectSet =
- EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
- if (effectSet) {
- effectSet->RemoveEffect(*this);
- if (effectSet->IsEmpty()) {
- EffectSet::DestroyEffectSet(mTarget->mElement, mTarget->mPseudoType);
- }
- }
-}
-
-void
-KeyframeEffectReadOnly::RequestRestyle(
- EffectCompositor::RestyleType aRestyleType)
-{
- nsPresContext* presContext = GetPresContext();
- if (presContext && mTarget && mAnimation) {
- presContext->EffectCompositor()->
- RequestRestyle(mTarget->mElement, mTarget->mPseudoType,
- aRestyleType, mAnimation->CascadeLevel());
- }
-}
-
-already_AddRefed<nsStyleContext>
-KeyframeEffectReadOnly::GetTargetStyleContext()
-{
- nsIPresShell* shell = GetPresShell();
- if (!shell) {
- return nullptr;
- }
-
- MOZ_ASSERT(mTarget,
- "Should only have a presshell when we have a target element");
-
- nsIAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count
- ? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType)
- : nullptr;
- return nsComputedDOMStyle::GetStyleContextForElement(mTarget->mElement,
- pseudo, shell);
-}
-
-#ifdef DEBUG
-void
-DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties)
-{
- for (auto& p : aAnimationProperties) {
- printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get());
- for (auto& s : p.mSegments) {
- nsString fromValue, toValue;
- Unused << StyleAnimationValue::UncomputeValue(p.mProperty,
- s.mFromValue,
- fromValue);
- Unused << StyleAnimationValue::UncomputeValue(p.mProperty,
- s.mToValue,
- toValue);
- printf(" %f..%f: %s..%s\n", s.mFromKey, s.mToKey,
- NS_ConvertUTF16toUTF8(fromValue).get(),
- NS_ConvertUTF16toUTF8(toValue).get());
- }
- }
-}
-#endif
-
-/* static */ already_AddRefed<KeyframeEffectReadOnly>
-KeyframeEffectReadOnly::Constructor(
- const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
- ErrorResult& aRv)
-{
- return ConstructKeyframeEffect<KeyframeEffectReadOnly>(aGlobal, aTarget,
- aKeyframes, aOptions,
- aRv);
-}
-
-void
-KeyframeEffectReadOnly::GetTarget(
- Nullable<OwningElementOrCSSPseudoElement>& aRv) const
-{
- if (!mTarget) {
- aRv.SetNull();
- return;
- }
-
- switch (mTarget->mPseudoType) {
- case CSSPseudoElementType::before:
- case CSSPseudoElementType::after:
- aRv.SetValue().SetAsCSSPseudoElement() =
- CSSPseudoElement::GetCSSPseudoElement(mTarget->mElement,
- mTarget->mPseudoType);
- break;
-
- case CSSPseudoElementType::NotPseudo:
- aRv.SetValue().SetAsElement() = mTarget->mElement;
- break;
-
- default:
- NS_NOTREACHED("Animation of unsupported pseudo-type");
- aRv.SetNull();
- }
-}
-
-static void
-CreatePropertyValue(nsCSSPropertyID aProperty,
- float aOffset,
- const Maybe<ComputedTimingFunction>& aTimingFunction,
- const StyleAnimationValue& aValue,
- AnimationPropertyValueDetails& aResult)
-{
- aResult.mOffset = aOffset;
-
- nsString stringValue;
- DebugOnly<bool> uncomputeResult =
- StyleAnimationValue::UncomputeValue(aProperty, aValue, stringValue);
- MOZ_ASSERT(uncomputeResult, "failed to uncompute value");
- aResult.mValue = stringValue;
-
- if (aTimingFunction) {
- aResult.mEasing.Construct();
- aTimingFunction->AppendToString(aResult.mEasing.Value());
- } else {
- aResult.mEasing.Construct(NS_LITERAL_STRING("linear"));
- }
-
- aResult.mComposite = CompositeOperation::Replace;
-}
-
-void
-KeyframeEffectReadOnly::GetProperties(
- nsTArray<AnimationPropertyDetails>& aProperties,
- ErrorResult& aRv) const
-{
- for (const AnimationProperty& property : mProperties) {
- AnimationPropertyDetails propertyDetails;
- propertyDetails.mProperty =
- NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty));
- propertyDetails.mRunningOnCompositor = property.mIsRunningOnCompositor;
-
- nsXPIDLString localizedString;
- if (property.mPerformanceWarning &&
- property.mPerformanceWarning->ToLocalizedString(localizedString)) {
- propertyDetails.mWarning.Construct(localizedString);
- }
-
- if (!propertyDetails.mValues.SetCapacity(property.mSegments.Length(),
- mozilla::fallible)) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- for (size_t segmentIdx = 0, segmentLen = property.mSegments.Length();
- segmentIdx < segmentLen;
- segmentIdx++)
- {
- const AnimationPropertySegment& segment = property.mSegments[segmentIdx];
-
- binding_detail::FastAnimationPropertyValueDetails fromValue;
- CreatePropertyValue(property.mProperty, segment.mFromKey,
- segment.mTimingFunction, segment.mFromValue,
- fromValue);
- // We don't apply timing functions for zero-length segments, so
- // don't return one here.
- if (segment.mFromKey == segment.mToKey) {
- fromValue.mEasing.Reset();
- }
- // The following won't fail since we have already allocated the capacity
- // above.
- propertyDetails.mValues.AppendElement(fromValue, mozilla::fallible);
-
- // Normally we can ignore the to-value for this segment since it is
- // identical to the from-value from the next segment. However, we need
- // to add it if either:
- // a) this is the last segment, or
- // b) the next segment's from-value differs.
- if (segmentIdx == segmentLen - 1 ||
- property.mSegments[segmentIdx + 1].mFromValue != segment.mToValue) {
- binding_detail::FastAnimationPropertyValueDetails toValue;
- CreatePropertyValue(property.mProperty, segment.mToKey,
- Nothing(), segment.mToValue, toValue);
- // It doesn't really make sense to have a timing function on the
- // last property value or before a sudden jump so we just drop the
- // easing property altogether.
- toValue.mEasing.Reset();
- propertyDetails.mValues.AppendElement(toValue, mozilla::fallible);
- }
- }
-
- aProperties.AppendElement(propertyDetails);
- }
-}
-
-void
-KeyframeEffectReadOnly::GetKeyframes(JSContext*& aCx,
- nsTArray<JSObject*>& aResult,
- ErrorResult& aRv)
-{
- MOZ_ASSERT(aResult.IsEmpty());
- MOZ_ASSERT(!aRv.Failed());
-
- if (!aResult.SetCapacity(mKeyframes.Length(), mozilla::fallible)) {
- aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
-
- for (const Keyframe& keyframe : mKeyframes) {
- // Set up a dictionary object for the explicit members
- BaseComputedKeyframe keyframeDict;
- if (keyframe.mOffset) {
- keyframeDict.mOffset.SetValue(keyframe.mOffset.value());
- }
- MOZ_ASSERT(keyframe.mComputedOffset != Keyframe::kComputedOffsetNotSet,
- "Invalid computed offset");
- keyframeDict.mComputedOffset.Construct(keyframe.mComputedOffset);
- if (keyframe.mTimingFunction) {
- keyframeDict.mEasing.Truncate();
- keyframe.mTimingFunction.ref().AppendToString(keyframeDict.mEasing);
- } // else if null, leave easing as its default "linear".
-
- JS::Rooted<JS::Value> keyframeJSValue(aCx);
- if (!ToJSValue(aCx, keyframeDict, &keyframeJSValue)) {
- aRv.Throw(NS_ERROR_FAILURE);
- return;
- }
-
- JS::Rooted<JSObject*> keyframeObject(aCx, &keyframeJSValue.toObject());
- for (const PropertyValuePair& propertyValue : keyframe.mPropertyValues) {
-
- const char* name = nsCSSProps::PropertyIDLName(propertyValue.mProperty);
-
- // nsCSSValue::AppendToString does not accept shorthands properties but
- // works with token stream values if we pass eCSSProperty_UNKNOWN as
- // the property.
- nsCSSPropertyID propertyForSerializing =
- nsCSSProps::IsShorthand(propertyValue.mProperty)
- ? eCSSProperty_UNKNOWN
- : propertyValue.mProperty;
-
- nsAutoString stringValue;
- propertyValue.mValue.AppendToString(
- propertyForSerializing, stringValue, nsCSSValue::eNormalized);
-
- JS::Rooted<JS::Value> value(aCx);
- if (!ToJSValue(aCx, stringValue, &value) ||
- !JS_DefineProperty(aCx, keyframeObject, name, value,
- JSPROP_ENUMERATE)) {
- aRv.Throw(NS_ERROR_FAILURE);
- return;
- }
- }
-
- aResult.AppendElement(keyframeObject);
- }
-}
-
-/* static */ const TimeDuration
-KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
-{
- // The amount of time we can wait between updating throttled animations
- // on the main thread that influence the overflow region.
- static const TimeDuration kOverflowRegionRefreshInterval =
- TimeDuration::FromMilliseconds(200);
-
- return kOverflowRegionRefreshInterval;
-}
-
-bool
-KeyframeEffectReadOnly::CanThrottle() const
-{
- // Unthrottle if we are not in effect or current. This will be the case when
- // our owning animation has finished, is idle, or when we are in the delay
- // phase (but without a backwards fill). In each case the computed progress
- // value produced on each tick will be the same so we will skip requesting
- // unnecessary restyles in NotifyAnimationTimingUpdated. Any calls we *do* get
- // here will be because of a change in state (e.g. we are newly finished or
- // newly no longer in effect) in which case we shouldn't throttle the sample.
- if (!IsInEffect() || !IsCurrent()) {
- return false;
- }
-
- nsIFrame* frame = GetAnimationFrame();
- if (!frame) {
- // There are two possible cases here.
- // a) No target element
- // b) The target element has no frame, e.g. because it is in a display:none
- // subtree.
- // In either case we can throttle the animation because there is no
- // need to update on the main thread.
- return true;
- }
-
- // We can throttle the animation if the animation is paint only and
- // the target frame is out of view or the document is in background tabs.
- if (CanIgnoreIfNotVisible()) {
- nsIPresShell* presShell = GetPresShell();
- if ((presShell && !presShell->IsActive()) ||
- frame->IsScrolledOutOfView()) {
- return true;
- }
- }
-
- // First we need to check layer generation and transform overflow
- // prior to the property.mIsRunningOnCompositor check because we should
- // occasionally unthrottle these animations even if the animations are
- // already running on compositor.
- for (const LayerAnimationInfo::Record& record :
- LayerAnimationInfo::sRecords) {
- // Skip properties that are overridden in the cascade.
- // (GetAnimationOfProperty, as called by HasAnimationOfProperty,
- // only returns an animation if it currently wins in the cascade.)
- if (!HasAnimationOfProperty(record.mProperty)) {
- continue;
- }
-
- EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
- mTarget->mPseudoType);
- MOZ_ASSERT(effectSet, "CanThrottle should be called on an effect "
- "associated with a target element");
- layers::Layer* layer =
- FrameLayerBuilder::GetDedicatedLayer(frame, record.mLayerType);
- // Unthrottle if the layer needs to be brought up to date
- if (!layer ||
- effectSet->GetAnimationGeneration() !=
- layer->GetAnimationGeneration()) {
- return false;
- }
-
- // If this is a transform animation that affects the overflow region,
- // we should unthrottle the animation periodically.
- if (record.mProperty == eCSSProperty_transform &&
- !CanThrottleTransformChanges(*frame)) {
- return false;
- }
- }
-
- for (const AnimationProperty& property : mProperties) {
- if (!property.mIsRunningOnCompositor) {
- return false;
- }
- }
-
- return true;
-}
-
-bool
-KeyframeEffectReadOnly::CanThrottleTransformChanges(nsIFrame& aFrame) const
-{
- // If we know that the animation cannot cause overflow,
- // we can just disable flushes for this animation.
-
- // If we don't show scrollbars, we don't care about overflow.
- if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
- return true;
- }
-
- nsPresContext* presContext = GetPresContext();
- // CanThrottleTransformChanges is only called as part of a refresh driver tick
- // in which case we expect to has a pres context.
- MOZ_ASSERT(presContext);
-
- TimeStamp now =
- presContext->RefreshDriver()->MostRecentRefresh();
-
- EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
- mTarget->mPseudoType);
- MOZ_ASSERT(effectSet, "CanThrottleTransformChanges is expected to be called"
- " on an effect in an effect set");
- MOZ_ASSERT(mAnimation, "CanThrottleTransformChanges is expected to be called"
- " on an effect with a parent animation");
- TimeStamp animationRuleRefreshTime =
- effectSet->AnimationRuleRefreshTime(mAnimation->CascadeLevel());
- // If this animation can cause overflow, we can throttle some of the ticks.
- if (!animationRuleRefreshTime.IsNull() &&
- (now - animationRuleRefreshTime) < OverflowRegionRefreshInterval()) {
- return true;
- }
-
- // If the nearest scrollable ancestor has overflow:hidden,
- // we don't care about overflow.
- nsIScrollableFrame* scrollable =
- nsLayoutUtils::GetNearestScrollableFrame(&aFrame);
- if (!scrollable) {
- return true;
- }
-
- ScrollbarStyles ss = scrollable->GetScrollbarStyles();
- if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
- ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
- scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
- return true;
- }
-
- return false;
-}
-
-nsIFrame*
-KeyframeEffectReadOnly::GetAnimationFrame() const
-{
- if (!mTarget) {
- return nullptr;
- }
-
- nsIFrame* frame = mTarget->mElement->GetPrimaryFrame();
- if (!frame) {
- return nullptr;
- }
-
- if (mTarget->mPseudoType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(frame);
- } else if (mTarget->mPseudoType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(frame);
- } else {
- MOZ_ASSERT(mTarget->mPseudoType == CSSPseudoElementType::NotPseudo,
- "unknown mTarget->mPseudoType");
- }
- if (!frame) {
- return nullptr;
- }
-
- return nsLayoutUtils::GetStyleFrame(frame);
-}
-
-nsIDocument*
-KeyframeEffectReadOnly::GetRenderedDocument() const
-{
- if (!mTarget) {
- return nullptr;
- }
- return mTarget->mElement->GetComposedDoc();
-}
-
-nsIPresShell*
-KeyframeEffectReadOnly::GetPresShell() const
-{
- nsIDocument* doc = GetRenderedDocument();
- if (!doc) {
- return nullptr;
- }
- return doc->GetShell();
-}
-
-nsPresContext*
-KeyframeEffectReadOnly::GetPresContext() const
-{
- nsIPresShell* shell = GetPresShell();
- if (!shell) {
- return nullptr;
- }
- return shell->GetPresContext();
-}
-
-/* static */ bool
-KeyframeEffectReadOnly::IsGeometricProperty(
- const nsCSSPropertyID aProperty)
-{
- switch (aProperty) {
- case eCSSProperty_bottom:
- case eCSSProperty_height:
- case eCSSProperty_left:
- case eCSSProperty_right:
- case eCSSProperty_top:
- case eCSSProperty_width:
- return true;
- default:
- return false;
- }
-}
-
-/* static */ bool
-KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
- const nsIFrame* aFrame,
- AnimationPerformanceWarning::Type& aPerformanceWarning)
-{
- // Disallow OMTA for preserve-3d transform. Note that we check the style property
- // rather than Extend3DContext() since that can recurse back into this function
- // via HasOpacity(). See bug 779598.
- if (aFrame->Combines3DTransformWithAncestors() ||
- aFrame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
- aPerformanceWarning = AnimationPerformanceWarning::Type::TransformPreserve3D;
- return false;
- }
- // Note that testing BackfaceIsHidden() is not a sufficient test for
- // what we need for animating backface-visibility correctly if we
- // remove the above test for Extend3DContext(); that would require
- // looking at backface-visibility on descendants as well. See bug 1186204.
- if (aFrame->BackfaceIsHidden()) {
- aPerformanceWarning =
- AnimationPerformanceWarning::Type::TransformBackfaceVisibilityHidden;
- return false;
- }
- // Async 'transform' animations of aFrames with SVG transforms is not
- // supported. See bug 779599.
- if (aFrame->IsSVGTransformed()) {
- aPerformanceWarning = AnimationPerformanceWarning::Type::TransformSVG;
- return false;
- }
-
- return true;
-}
-
-bool
-KeyframeEffectReadOnly::ShouldBlockAsyncTransformAnimations(
- const nsIFrame* aFrame,
- AnimationPerformanceWarning::Type& aPerformanceWarning) const
-{
- // We currently only expect this method to be called when this effect
- // is attached to a playing Animation. If that ever changes we'll need
- // to update this to only return true when that is the case since paused,
- // filling, cancelled Animations etc. shouldn't stop other Animations from
- // running on the compositor.
- MOZ_ASSERT(mAnimation && mAnimation->IsPlaying());
-
- for (const AnimationProperty& property : mProperties) {
- // If a property is overridden in the CSS cascade, it should not block other
- // animations from running on the compositor.
- if (!property.mWinsInCascade) {
- continue;
- }
- // Check for geometric properties
- if (IsGeometricProperty(property.mProperty)) {
- aPerformanceWarning =
- AnimationPerformanceWarning::Type::TransformWithGeometricProperties;
- return true;
- }
-
- // Check for unsupported transform animations
- if (property.mProperty == eCSSProperty_transform) {
- if (!CanAnimateTransformOnCompositor(aFrame,
- aPerformanceWarning)) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-void
-KeyframeEffectReadOnly::SetPerformanceWarning(
- nsCSSPropertyID aProperty,
- const AnimationPerformanceWarning& aWarning)
-{
- for (AnimationProperty& property : mProperties) {
- if (property.mProperty == aProperty &&
- (!property.mPerformanceWarning ||
- *property.mPerformanceWarning != aWarning)) {
- property.mPerformanceWarning = Some(aWarning);
-
- nsXPIDLString localizedString;
- if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
- property.mPerformanceWarning->ToLocalizedString(localizedString)) {
- nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
- AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement);
- }
- return;
- }
- }
-}
-
-static already_AddRefed<nsStyleContext>
-CreateStyleContextForAnimationValue(nsCSSPropertyID aProperty,
- const StyleAnimationValue& aValue,
- nsStyleContext* aBaseStyleContext)
-{
- MOZ_ASSERT(aBaseStyleContext,
- "CreateStyleContextForAnimationValue needs to be called "
- "with a valid nsStyleContext");
-
- RefPtr<AnimValuesStyleRule> styleRule = new AnimValuesStyleRule();
- styleRule->AddValue(aProperty, aValue);
-
- nsCOMArray<nsIStyleRule> rules;
- rules.AppendObject(styleRule);
-
- MOZ_ASSERT(aBaseStyleContext->PresContext()->StyleSet()->IsGecko(),
- "ServoStyleSet should not use StyleAnimationValue for animations");
- nsStyleSet* styleSet =
- aBaseStyleContext->PresContext()->StyleSet()->AsGecko();
-
- RefPtr<nsStyleContext> styleContext =
- styleSet->ResolveStyleByAddingRules(aBaseStyleContext, rules);
-
- // We need to call StyleData to generate cached data for the style context.
- // Otherwise CalcStyleDifference returns no meaningful result.
- styleContext->StyleData(nsCSSProps::kSIDTable[aProperty]);
-
- return styleContext.forget();
-}
-
-void
-KeyframeEffectReadOnly::CalculateCumulativeChangeHint(
- nsStyleContext *aStyleContext)
-{
- mCumulativeChangeHint = nsChangeHint(0);
-
- for (const AnimationProperty& property : mProperties) {
- for (const AnimationPropertySegment& segment : property.mSegments) {
- RefPtr<nsStyleContext> fromContext =
- CreateStyleContextForAnimationValue(property.mProperty,
- segment.mFromValue, aStyleContext);
-
- RefPtr<nsStyleContext> toContext =
- CreateStyleContextForAnimationValue(property.mProperty,
- segment.mToValue, aStyleContext);
-
- uint32_t equalStructs = 0;
- uint32_t samePointerStructs = 0;
- nsChangeHint changeHint =
- fromContext->CalcStyleDifference(toContext,
- nsChangeHint(0),
- &equalStructs,
- &samePointerStructs);
-
- mCumulativeChangeHint |= changeHint;
- }
- }
-}
-
-void
-KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation)
-{
- if (mAnimation == aAnimation) {
- return;
- }
-
- // Restyle for the old animation.
- RequestRestyle(EffectCompositor::RestyleType::Layer);
-
- mAnimation = aAnimation;
-
- // The order of these function calls is important:
- // NotifyAnimationTimingUpdated() need the updated mIsRelevant flag to check
- // if it should create the effectSet or not, and MarkCascadeNeedsUpdate()
- // needs a valid effectSet, so we should call them in this order.
- if (mAnimation) {
- mAnimation->UpdateRelevance();
- }
- NotifyAnimationTimingUpdated();
- if (mAnimation) {
- MarkCascadeNeedsUpdate();
- }
-}
-
-bool
-KeyframeEffectReadOnly::CanIgnoreIfNotVisible() const
-{
- if (!AnimationUtils::IsOffscreenThrottlingEnabled()) {
- return false;
- }
-
- // FIXME: For further sophisticated optimization we need to check
- // change hint on the segment corresponding to computedTiming.progress.
- return NS_IsHintSubset(
- mCumulativeChangeHint, nsChangeHint_Hints_CanIgnoreIfNotVisible);
-}
-
-void
-KeyframeEffectReadOnly::MaybeUpdateFrameForCompositor()
-{
- nsIFrame* frame = GetAnimationFrame();
- if (!frame) {
- return;
- }
-
- // We don't check mWinsInCascade flag here because, at this point,
- // UpdateCascadeResults has not yet run.
- // FIXME: Bug 1272495: If this effect does not win in the cascade, the
- // NS_FRAME_MAY_BE_TRANSFORMED flag should be removed when the animation
- // will be removed from effect set or the transform keyframes are removed
- // by setKeyframes. The latter case will be hard to solve though.
- for (const AnimationProperty& property : mProperties) {
- if (property.mProperty == eCSSProperty_transform) {
- frame->AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
- return;
- }
- }
-}
-
-void
-KeyframeEffectReadOnly::MarkCascadeNeedsUpdate()
-{
- if (!mTarget) {
- return;
- }
-
- EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
- mTarget->mPseudoType);
- if (!effectSet) {
- return;
- }
- effectSet->MarkCascadeNeedsUpdate();
-}
-
-//---------------------------------------------------------------------
-//
-// KeyframeEffect
-//
-//---------------------------------------------------------------------
-
KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
const Maybe<OwningAnimationTarget>& aTarget,
const TimingParams& aTiming,
const KeyframeEffectParams& aOptions)
: KeyframeEffectReadOnly(aDocument, aTarget,
new AnimationEffectTiming(aDocument, aTiming, this),
aOptions)
{
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -2,399 +2,37 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_KeyframeEffect_h
#define mozilla_dom_KeyframeEffect_h
-#include "nsChangeHint.h"
-#include "nsCSSPropertyID.h"
-#include "nsCSSValue.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsTArray.h"
#include "nsWrapperCache.h"
-#include "mozilla/AnimationPerformanceWarning.h"
-#include "mozilla/AnimationTarget.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/ComputedTimingFunction.h"
-#include "mozilla/EffectCompositor.h"
-#include "mozilla/KeyframeEffectParams.h"
-#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
-#include "mozilla/StyleAnimationValue.h"
-#include "mozilla/dom/AnimationEffectReadOnly.h"
-#include "mozilla/dom/Element.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
+#include "mozilla/AnimationTarget.h" // For (Non)OwningAnimationTarget
+#include "mozilla/Maybe.h"
struct JSContext;
-class nsCSSPropertyIDSet;
-class nsIContent;
+class JSObject;
class nsIDocument;
-class nsIFrame;
-class nsIPresShell;
-class nsPresContext;
namespace mozilla {
-class AnimValuesStyleRule;
-enum class CSSPseudoElementType : uint8_t;
-
-namespace dom {
-class ElementOrCSSPseudoElement;
-class OwningElementOrCSSPseudoElement;
-class UnrestrictedDoubleOrKeyframeAnimationOptions;
-class UnrestrictedDoubleOrKeyframeEffectOptions;
-enum class IterationCompositeOperation : uint32_t;
-enum class CompositeOperation : uint32_t;
-struct AnimationPropertyDetails;
-}
-
-/**
- * A property-value pair specified on a keyframe.
- */
-struct PropertyValuePair
-{
- nsCSSPropertyID mProperty;
- // The specified value for the property. For shorthand properties or invalid
- // property values, we store the specified property value as a token stream
- // (string).
- nsCSSValue mValue;
-
- bool operator==(const PropertyValuePair& aOther) const {
- return mProperty == aOther.mProperty &&
- mValue == aOther.mValue;
- }
-};
-
-/**
- * A single keyframe.
- *
- * This is the canonical form in which keyframe effects are stored and
- * corresponds closely to the type of objects returned via the getKeyframes()
- * API.
- *
- * Before computing an output animation value, however, we flatten these frames
- * down to a series of per-property value arrays where we also resolve any
- * overlapping shorthands/longhands, convert specified CSS values to computed
- * values, etc.
- *
- * When the target element or style context changes, however, we rebuild these
- * per-property arrays from the original list of keyframes objects. As a result,
- * these objects represent the master definition of the effect's values.
- */
-struct Keyframe
-{
- Keyframe() = default;
- Keyframe(const Keyframe& aOther) = default;
- Keyframe(Keyframe&& aOther)
- {
- *this = Move(aOther);
- }
-
- Keyframe& operator=(const Keyframe& aOther) = default;
- Keyframe& operator=(Keyframe&& aOther)
- {
- mOffset = aOther.mOffset;
- mComputedOffset = aOther.mComputedOffset;
- mTimingFunction = Move(aOther.mTimingFunction);
- mPropertyValues = Move(aOther.mPropertyValues);
- return *this;
- }
-
- Maybe<double> mOffset;
- static constexpr double kComputedOffsetNotSet = -1.0;
- double mComputedOffset = kComputedOffsetNotSet;
- Maybe<ComputedTimingFunction> mTimingFunction; // Nothing() here means
- // "linear"
- nsTArray<PropertyValuePair> mPropertyValues;
-};
-
-struct AnimationPropertySegment
-{
- float mFromKey, mToKey;
- StyleAnimationValue mFromValue, mToValue;
- Maybe<ComputedTimingFunction> mTimingFunction;
-
- bool operator==(const AnimationPropertySegment& aOther) const {
- return mFromKey == aOther.mFromKey &&
- mToKey == aOther.mToKey &&
- mFromValue == aOther.mFromValue &&
- mToValue == aOther.mToValue &&
- mTimingFunction == aOther.mTimingFunction;
- }
- bool operator!=(const AnimationPropertySegment& aOther) const {
- return !(*this == aOther);
- }
-};
-
-struct AnimationProperty
-{
- nsCSSPropertyID mProperty = eCSSProperty_UNKNOWN;
-
- // Does this property win in the CSS Cascade?
- //
- // For CSS transitions, this is true as long as a CSS animation on the
- // same property and element is not running, in which case we set this
- // to false so that the animation (lower in the cascade) can win. We
- // then use this to decide whether to apply the style both in the CSS
- // cascade and for OMTA.
- //
- // For CSS Animations, which are overridden by !important rules in the
- // cascade, we actually determine this from the CSS cascade
- // computations, and then use it for OMTA.
- //
- // **NOTE**: This member is not included when comparing AnimationProperty
- // objects for equality.
- bool mWinsInCascade = false;
-
- // If true, the propery is currently being animated on the compositor.
- //
- // Note that when the owning Animation requests a non-throttled restyle, in
- // between calling RequestRestyle on its EffectCompositor and when the
- // restyle is performed, this member may temporarily become false even if
- // the animation remains on the layer after the restyle.
- //
- // **NOTE**: This member is not included when comparing AnimationProperty
- // objects for equality.
- bool mIsRunningOnCompositor = false;
-
- Maybe<AnimationPerformanceWarning> mPerformanceWarning;
-
- InfallibleTArray<AnimationPropertySegment> mSegments;
-
- // NOTE: This operator does *not* compare the mWinsInCascade member *or* the
- // mIsRunningOnCompositor member.
- // This is because AnimationProperty objects are compared when recreating
- // CSS animations to determine if mutation observer change records need to
- // be created or not. However, at the point when these objects are compared
- // neither the mWinsInCascade nor the mIsRunningOnCompositor will have been
- // set on the new objects so we ignore these members to avoid generating
- // spurious change records.
- bool operator==(const AnimationProperty& aOther) const {
- return mProperty == aOther.mProperty &&
- mSegments == aOther.mSegments;
- }
- bool operator!=(const AnimationProperty& aOther) const {
- return !(*this == aOther);
- }
-};
-
-struct ElementPropertyTransition;
+class ErrorResult;
+struct KeyframeEffectParams;
+struct TimingParams;
namespace dom {
-class Animation;
-
-class KeyframeEffectReadOnly : public AnimationEffectReadOnly
-{
-public:
- KeyframeEffectReadOnly(nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- const TimingParams& aTiming,
- const KeyframeEffectParams& aOptions);
-
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
- AnimationEffectReadOnly)
-
- virtual JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- KeyframeEffectReadOnly* AsKeyframeEffect() override { return this; }
-
- // KeyframeEffectReadOnly interface
- static already_AddRefed<KeyframeEffectReadOnly>
- Constructor(const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
- ErrorResult& aRv);
-
- void GetTarget(Nullable<OwningElementOrCSSPseudoElement>& aRv) const;
- Maybe<NonOwningAnimationTarget> GetTarget() const
- {
- Maybe<NonOwningAnimationTarget> result;
- if (mTarget) {
- result.emplace(*mTarget);
- }
- return result;
- }
- void GetKeyframes(JSContext*& aCx,
- nsTArray<JSObject*>& aResult,
- ErrorResult& aRv);
- void GetProperties(nsTArray<AnimationPropertyDetails>& aProperties,
- ErrorResult& aRv) const;
-
- IterationCompositeOperation IterationComposite() const;
- CompositeOperation Composite() const;
- void GetSpacing(nsString& aRetVal) const
- {
- mEffectOptions.GetSpacingAsString(aRetVal);
- }
-
- void NotifyAnimationTimingUpdated();
-
- void SetAnimation(Animation* aAnimation) override;
-
- void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
- ErrorResult& aRv);
- void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
- nsStyleContext* aStyleContext);
- const AnimationProperty*
- GetAnimationOfProperty(nsCSSPropertyID aProperty) const;
- bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const
- {
- return GetAnimationOfProperty(aProperty) != nullptr;
- }
- const InfallibleTArray<AnimationProperty>& Properties() const
- {
- return mProperties;
- }
- InfallibleTArray<AnimationProperty>& Properties()
- {
- return mProperties;
- }
-
- // Update |mProperties| by recalculating from |mKeyframes| using
- // |aStyleContext| to resolve specified values.
- void UpdateProperties(nsStyleContext* aStyleContext);
-
- // Updates |aStyleRule| with the animation values produced by this
- // AnimationEffect for the current time except any properties already
- // contained in |aSetProperties|.
- // Any updated properties are added to |aSetProperties|.
- void ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
- nsCSSPropertyIDSet& aSetProperties);
- // Returns true if at least one property is being animated on compositor.
- bool IsRunningOnCompositor() const;
- void SetIsRunningOnCompositor(nsCSSPropertyID aProperty, bool aIsRunning);
- void ResetIsRunningOnCompositor();
-
- // Returns true if this effect, applied to |aFrame|, contains properties
- // that mean we shouldn't run transform compositor animations on this element.
- //
- // For example, if we have an animation of geometric properties like 'left'
- // and 'top' on an element, we force all 'transform' animations running at
- // the same time on the same element to run on the main thread.
- //
- // When returning true, |aPerformanceWarning| stores the reason why
- // we shouldn't run the transform animations.
- bool ShouldBlockAsyncTransformAnimations(
- const nsIFrame* aFrame,
- AnimationPerformanceWarning::Type& aPerformanceWarning) const;
-
- nsIDocument* GetRenderedDocument() const;
- nsPresContext* GetPresContext() const;
- nsIPresShell* GetPresShell() const;
-
- // Associates a warning with the animated property on the specified frame
- // indicating why, for example, the property could not be animated on the
- // compositor. |aParams| and |aParamsLength| are optional parameters which
- // will be used to generate a localized message for devtools.
- void SetPerformanceWarning(
- nsCSSPropertyID aProperty,
- const AnimationPerformanceWarning& aWarning);
-
- // Cumulative change hint on each segment for each property.
- // This is used for deciding the animation is paint-only.
- void CalculateCumulativeChangeHint(nsStyleContext* aStyleContext);
-
- // Returns true if all of animation properties' change hints
- // can ignore painting if the animation is not visible.
- // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
- // in detail which change hint can be ignored.
- bool CanIgnoreIfNotVisible() const;
-
-protected:
- KeyframeEffectReadOnly(nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- AnimationEffectTimingReadOnly* aTiming,
- const KeyframeEffectParams& aOptions);
-
- ~KeyframeEffectReadOnly() override = default;
-
- template<class KeyframeEffectType, class OptionsType>
- static already_AddRefed<KeyframeEffectType>
- ConstructKeyframeEffect(const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const OptionsType& aOptions,
- ErrorResult& aRv);
-
- // 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
- // changes with regards to this effects's timing including changes to the
- // owning Animation's timing.
- void UpdateTargetRegistration();
-
- // Remove the current effect target from its EffectSet.
- void UnregisterTarget();
-
- void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
-
- // Update the associated frame state bits so that, if necessary, a stacking
- // context will be created and the effect sent to the compositor. We
- // typically need to do this when the properties referenced by the keyframe
- // have changed, or when the target frame might have changed.
- void MaybeUpdateFrameForCompositor();
-
- // Looks up the style context associated with the target element, if any.
- // 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.
- already_AddRefed<nsStyleContext>
- GetTargetStyleContext();
-
- // A wrapper for marking cascade update according to the current
- // target and its effectSet.
- void MarkCascadeNeedsUpdate();
-
- Maybe<OwningAnimationTarget> mTarget;
-
- KeyframeEffectParams mEffectOptions;
-
- // The specified keyframes.
- nsTArray<Keyframe> mKeyframes;
-
- // A set of per-property value arrays, derived from |mKeyframes|.
- nsTArray<AnimationProperty> mProperties;
-
- // 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
- // timing function) so we can avoid unnecessary style updates.
- Nullable<double> mProgressOnLastCompose;
-
- // We need to track when we go to or from being "in effect" since
- // we need to re-evaluate the cascade of animations when that changes.
- bool mInEffectOnLastAnimationTimingUpdate;
-
-private:
- nsChangeHint mCumulativeChangeHint;
-
- nsIFrame* GetAnimationFrame() const;
-
- bool CanThrottle() const;
- bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
-
- // Returns true unless Gecko limitations prevent performing transform
- // animations for |aFrame|. When returning true, the reason for the
- // limitation is stored in |aOutPerformanceWarning|.
- static bool CanAnimateTransformOnCompositor(
- const nsIFrame* aFrame,
- AnimationPerformanceWarning::Type& aPerformanceWarning);
- static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
-
- static const TimeDuration OverflowRegionRefreshInterval();
-};
+class ElementOrCSSPseudoElement;
+class GlobalObject;
+class UnrestrictedDoubleOrKeyframeAnimationOptions;
+class UnrestrictedDoubleOrKeyframeEffectOptions;
class KeyframeEffect : public KeyframeEffectReadOnly
{
public:
KeyframeEffect(nsIDocument* aDocument,
const Maybe<OwningAnimationTarget>& aTarget,
const TimingParams& aTiming,
const KeyframeEffectParams& aOptions);
copy from dom/animation/KeyframeEffect.cpp
copy to dom/animation/KeyframeEffectReadOnly.cpp
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -1,34 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/dom/AnimatableBinding.h"
-#include "mozilla/dom/AnimationEffectTiming.h"
+ // For UnrestrictedDoubleOrKeyframeAnimationOptions;
#include "mozilla/dom/CSSPseudoElement.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/EffectSet.h"
-#include "mozilla/FloatingPoint.h"
+#include "mozilla/FloatingPoint.h" // For IsFinite
#include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt
#include "mozilla/KeyframeUtils.h"
#include "mozilla/StyleAnimationValue.h"
#include "Layers.h" // For Layer
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContextForElement
#include "nsContentUtils.h" // nsContentUtils::ReportToConsole
#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
-#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
-#include "nsIPresShell.h" // For nsIPresShell
+#include "nsIPresShell.h"
#include "nsIScriptError.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly,
mTarget)
@@ -482,18 +481,19 @@ KeyframeEffectParamsFromUnion(const Opti
result.mSpacingMode,
result.mPacedProperty,
aInvalidPacedProperty,
aRv);
}
return result;
}
-static Maybe<OwningAnimationTarget>
-ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
+/* static */ Maybe<OwningAnimationTarget>
+KeyframeEffectReadOnly::ConvertTarget(
+ const Nullable<ElementOrCSSPseudoElement>& aTarget)
{
// Return value optimization.
Maybe<OwningAnimationTarget> result;
if (aTarget.IsNull()) {
return result;
}
@@ -1275,125 +1275,10 @@ KeyframeEffectReadOnly::MarkCascadeNeeds
EffectSet* effectSet = EffectSet::GetEffectSet(mTarget->mElement,
mTarget->mPseudoType);
if (!effectSet) {
return;
}
effectSet->MarkCascadeNeedsUpdate();
}
-//---------------------------------------------------------------------
-//
-// KeyframeEffect
-//
-//---------------------------------------------------------------------
-
-KeyframeEffect::KeyframeEffect(nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- const TimingParams& aTiming,
- const KeyframeEffectParams& aOptions)
- : KeyframeEffectReadOnly(aDocument, aTarget,
- new AnimationEffectTiming(aDocument, aTiming, this),
- aOptions)
-{
-}
-
-JSObject*
-KeyframeEffect::WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto)
-{
- return KeyframeEffectBinding::Wrap(aCx, this, aGivenProto);
-}
-
-/* static */ already_AddRefed<KeyframeEffect>
-KeyframeEffect::Constructor(
- const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
- ErrorResult& aRv)
-{
- return ConstructKeyframeEffect<KeyframeEffect>(aGlobal, aTarget, aKeyframes,
- aOptions, aRv);
-}
-
-/* static */ already_AddRefed<KeyframeEffect>
-KeyframeEffect::Constructor(
- const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
- ErrorResult& aRv)
-{
- return ConstructKeyframeEffect<KeyframeEffect>(aGlobal, aTarget, aKeyframes,
- aOptions, aRv);
-}
-
-void
-KeyframeEffect::NotifySpecifiedTimingUpdated()
-{
- // Use the same document for a pseudo element and its parent element.
- // Use nullptr if we don't have mTarget, so disable the mutation batch.
- nsAutoAnimationMutationBatch mb(mTarget ? mTarget->mElement->OwnerDoc()
- : nullptr);
-
- if (mAnimation) {
- mAnimation->NotifyEffectTimingUpdated();
-
- if (mAnimation->IsRelevant()) {
- nsNodeUtils::AnimationChanged(mAnimation);
- }
-
- RequestRestyle(EffectCompositor::RestyleType::Layer);
- }
-}
-
-void
-KeyframeEffect::SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget)
-{
- Maybe<OwningAnimationTarget> newTarget = ConvertTarget(aTarget);
- if (mTarget == newTarget) {
- // Assign the same target, skip it.
- return;
- }
-
- if (mTarget) {
- UnregisterTarget();
- ResetIsRunningOnCompositor();
- // We don't need to reset the mWinsInCascade member since it will be updated
- // when we later associate with a different target (and until that time this
- // flag is not used).
-
- RequestRestyle(EffectCompositor::RestyleType::Layer);
-
- nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
- if (mAnimation) {
- nsNodeUtils::AnimationRemoved(mAnimation);
- }
- }
-
- mTarget = newTarget;
-
- if (mTarget) {
- UpdateTargetRegistration();
- RefPtr<nsStyleContext> styleContext = GetTargetStyleContext();
- if (styleContext) {
- UpdateProperties(styleContext);
- } else if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
- KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
- }
-
- MaybeUpdateFrameForCompositor();
-
- RequestRestyle(EffectCompositor::RestyleType::Layer);
-
- nsAutoAnimationMutationBatch mb(mTarget->mElement->OwnerDoc());
- if (mAnimation) {
- nsNodeUtils::AnimationAdded(mAnimation);
- }
- } else if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
- // New target is null, so fall back to distribute spacing.
- KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
- }
-}
-
} // namespace dom
} // namespace mozilla
copy from dom/animation/KeyframeEffect.h
copy to dom/animation/KeyframeEffectReadOnly.h
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -1,16 +1,16 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef mozilla_dom_KeyframeEffect_h
-#define mozilla_dom_KeyframeEffect_h
+#ifndef mozilla_dom_KeyframeEffectReadOnly_h
+#define mozilla_dom_KeyframeEffectReadOnly_h
#include "nsChangeHint.h"
#include "nsCSSPropertyID.h"
#include "nsCSSValue.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "mozilla/AnimationPerformanceWarning.h"
@@ -20,30 +20,34 @@
#include "mozilla/EffectCompositor.h"
#include "mozilla/KeyframeEffectParams.h"
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/AnimationEffectReadOnly.h"
#include "mozilla/dom/Element.h"
struct JSContext;
+class JSObject;
class nsCSSPropertyIDSet;
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsIPresShell;
class nsPresContext;
namespace mozilla {
class AnimValuesStyleRule;
enum class CSSPseudoElementType : uint8_t;
+class ErrorResult;
+struct TimingParams;
namespace dom {
class ElementOrCSSPseudoElement;
+class GlobalObject;
class OwningElementOrCSSPseudoElement;
class UnrestrictedDoubleOrKeyframeAnimationOptions;
class UnrestrictedDoubleOrKeyframeEffectOptions;
enum class IterationCompositeOperation : uint32_t;
enum class CompositeOperation : uint32_t;
struct AnimationPropertyDetails;
}
@@ -306,16 +310,19 @@ public:
protected:
KeyframeEffectReadOnly(nsIDocument* aDocument,
const Maybe<OwningAnimationTarget>& aTarget,
AnimationEffectTimingReadOnly* aTiming,
const KeyframeEffectParams& aOptions);
~KeyframeEffectReadOnly() override = default;
+ static Maybe<OwningAnimationTarget>
+ ConvertTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
+
template<class KeyframeEffectType, class OptionsType>
static already_AddRefed<KeyframeEffectType>
ConstructKeyframeEffect(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aKeyframes,
const OptionsType& aOptions,
ErrorResult& aRv);
@@ -386,50 +393,12 @@ private:
static bool CanAnimateTransformOnCompositor(
const nsIFrame* aFrame,
AnimationPerformanceWarning::Type& aPerformanceWarning);
static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
static const TimeDuration OverflowRegionRefreshInterval();
};
-class KeyframeEffect : public KeyframeEffectReadOnly
-{
-public:
- KeyframeEffect(nsIDocument* aDocument,
- const Maybe<OwningAnimationTarget>& aTarget,
- const TimingParams& aTiming,
- const KeyframeEffectParams& aOptions);
-
- JSObject* WrapObject(JSContext* aCx,
- JS::Handle<JSObject*> aGivenProto) override;
-
- static already_AddRefed<KeyframeEffect>
- Constructor(const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
- ErrorResult& aRv);
-
- // Variant of Constructor that accepts a KeyframeAnimationOptions object
- // for use with for Animatable.animate.
- // Not exposed to content.
- static already_AddRefed<KeyframeEffect>
- Constructor(const GlobalObject& aGlobal,
- const Nullable<ElementOrCSSPseudoElement>& aTarget,
- JS::Handle<JSObject*> aKeyframes,
- const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
- ErrorResult& aRv);
-
- void NotifySpecifiedTimingUpdated();
-
- // This method calls GetTargetStyleContext 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);
-};
-
} // namespace dom
} // namespace mozilla
-#endif // mozilla_dom_KeyframeEffect_h
+#endif // mozilla_dom_KeyframeEffectReadOnly_h
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -3,22 +3,23 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/KeyframeUtils.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/Move.h"
+#include "mozilla/RangedArray.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimingParams.h"
#include "mozilla/dom/BaseKeyframeTypesBinding.h" // For FastBaseKeyframe etc.
#include "mozilla/dom/Element.h"
-#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h" // For PropertyValuesPair etc.
#include "jsapi.h" // For ForOfIterator etc.
#include "nsClassHashtable.h"
#include "nsCSSParser.h"
#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h"
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsTArray.h"
#include <algorithm> // For std::stable_sort
--- a/dom/animation/moz.build
+++ b/dom/animation/moz.build
@@ -11,16 +11,17 @@ EXPORTS.mozilla.dom += [
'Animation.h',
'AnimationEffectReadOnly.h',
'AnimationEffectTiming.h',
'AnimationEffectTimingReadOnly.h',
'AnimationTimeline.h',
'CSSPseudoElement.h',
'DocumentTimeline.h',
'KeyframeEffect.h',
+ 'KeyframeEffectReadOnly.h',
]
EXPORTS.mozilla += [
'AnimationComparator.h',
'AnimationPerformanceWarning.h',
'AnimationTarget.h',
'AnimationUtils.h',
'AnimValuesStyleRule.h',
@@ -46,16 +47,17 @@ UNIFIED_SOURCES += [
'AnimValuesStyleRule.cpp',
'ComputedTimingFunction.cpp',
'CSSPseudoElement.cpp',
'DocumentTimeline.cpp',
'EffectCompositor.cpp',
'EffectSet.cpp',
'KeyframeEffect.cpp',
'KeyframeEffectParams.cpp',
+ 'KeyframeEffectReadOnly.cpp',
'KeyframeUtils.cpp',
'PendingAnimationTracker.cpp',
'TimingParams.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
'/layout/base',
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -134,16 +134,17 @@
#include "nsStyledElement.h"
#include "nsXBLService.h"
#include "nsITextControlElement.h"
#include "nsITextControlFrame.h"
#include "nsISupportsImpl.h"
#include "mozilla/dom/CSSPseudoElement.h"
#include "mozilla/dom/DocumentFragment.h"
+#include "mozilla/dom/KeyframeEffect.h"
#include "mozilla/dom/KeyframeEffectBinding.h"
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/VRDisplay.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
#include "nsComputedDOMStyle.h"
#include "nsDOMStringMap.h"
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -6,17 +6,17 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/Maybe.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/Animation.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsContentUtils.h"
#include "nsCSSPseudoElements.h"
#include "nsError.h"
#include "nsIDOMMutationEvent.h"
#include "nsIScriptGlobalObject.h"
#include "nsServiceManagerUtils.h"
#include "nsTextFragment.h"
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -24,17 +24,17 @@
#endif
#include "nsBindingManager.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/Animation.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLMediaElement.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsWrapperCacheInlines.h"
#include "nsObjectLoadingContent.h"
#include "nsDOMMutationObserver.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/ShadowRoot.h"
using namespace mozilla;
--- a/dom/webidl/KeyframeEffect.webidl
+++ b/dom/webidl/KeyframeEffect.webidl
@@ -19,18 +19,17 @@ dictionary KeyframeEffectOptions : Anima
IterationCompositeOperation iterationComposite = "replace";
CompositeOperation composite = "replace";
DOMString spacing = "distribute";
};
// Bug 1241783: For the constructor we use (Element or CSSPseudoElement)? for
// the first argument since we cannot convert a mixin into a union type
// automatically.
-[HeaderFile="mozilla/dom/KeyframeEffect.h",
- Func="nsDocument::IsWebAnimationsEnabled",
+[Func="nsDocument::IsWebAnimationsEnabled",
Constructor((Element or CSSPseudoElement)? target,
object? keyframes,
optional (unrestricted double or KeyframeEffectOptions) options)]
interface KeyframeEffectReadOnly : AnimationEffectReadOnly {
// Bug 1241783: As with the constructor, we use (Element or CSSPseudoElement)?
// for the type of |target| instead of Animatable?
readonly attribute (Element or CSSPseudoElement)? target;
readonly attribute IterationCompositeOperation iterationComposite;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -8,25 +8,27 @@
#include "Layers.h"
#include <algorithm> // for max, min
#include "apz/src/AsyncPanZoomController.h"
#include "CompositableHost.h" // for CompositableHost
#include "ImageContainer.h" // for ImageContainer, etc
#include "ImageLayers.h" // for ImageLayer
#include "LayerSorter.h" // for SortLayersBy3DZOrder
#include "LayersLogging.h" // for AppendToString
+#include "LayerUserData.h"
#include "ReadbackLayer.h" // for ReadbackLayer
#include "UnitTransforms.h" // for ViewAs
#include "gfxEnv.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "gfxPrefs.h"
#include "gfxUtils.h" // for gfxUtils, etc
#include "gfx2DGlue.h"
#include "mozilla/DebugOnly.h" // for DebugOnly
#include "mozilla/Telemetry.h" // for Accumulate
+#include "mozilla/ToString.h"
#include "mozilla/dom/Animation.h" // for ComputedTimingFunction
#include "mozilla/gfx/2D.h" // for DrawTarget
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/layers/CompositableClient.h" // for CompositableClient
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorTypes.h"
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -9,17 +9,17 @@
#include "apz/src/AsyncPanZoomController.h"
#include "FrameMetrics.h" // for FrameMetrics
#include "LayerManagerComposite.h" // for LayerManagerComposite, etc
#include "Layers.h" // for Layer, ContainerLayer, etc
#include "gfxPoint.h" // for gfxPoint, gfxSize
#include "gfxPrefs.h" // for gfxPrefs
#include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
#include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation
-#include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadOnly
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for dom::FillMode
#include "mozilla/gfx/BaseRect.h" // for BaseRect
#include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped
#include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped
#include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor
#include "mozilla/layers/APZUtils.h" // for CompleteAsyncTransform
#include "mozilla/layers/Compositor.h" // for Compositor
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent, etc
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -1,16 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ActiveLayerTracker.h"
#include "mozilla/ArrayUtils.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/EffectSet.h"
#include "mozilla/PodOperations.h"
#include "gfx2DGlue.h"
#include "nsExpirationTracker.h"
#include "nsContainerFrame.h"
#include "nsIContent.h"
#include "nsRefreshDriver.h"
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -13,17 +13,17 @@
#include "nsDisplayList.h"
#include <stdint.h>
#include <algorithm>
#include <limits>
#include "gfxUtils.h"
#include "mozilla/dom/TabChild.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/PLayerTransaction.h"
#include "nsCSSRendering.h"
#include "nsRenderingContext.h"
#include "nsISelectionController.h"
#include "nsIPresShell.h"
#include "nsRegion.h"
#include "nsStyleStructInlines.h"
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -65,17 +65,17 @@
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsICanvasRenderingContextInternal.h"
#include "gfxPlatform.h"
#include <algorithm>
#include <limits>
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/DOMRect.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "imgIRequest.h"
#include "nsIImageLoadingContent.h"
#include "nsCOMPtr.h"
#include "nsCSSProps.h"
#include "nsListControlFrame.h"
#include "mozilla/dom/Element.h"
#include "nsCanvasFrame.h"
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -16,17 +16,17 @@
#include "nsIFrame.h"
#include "nsLayoutUtils.h"
#include "FrameLayerBuilder.h"
#include "nsDisplayList.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/MemoryReporting.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsRuleProcessorData.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
using mozilla::dom::Animation;
using mozilla::dom::KeyframeEffectReadOnly;
namespace mozilla {
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -7,17 +7,17 @@
#include "nsTransitionManager.h"
#include "mozilla/dom/CSSAnimationBinding.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/EffectSet.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/dom/DocumentTimeline.h"
-#include "mozilla/dom/KeyframeEffect.h"
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "nsPresContext.h"
#include "nsStyleSet.h"
#include "nsStyleChangeList.h"
#include "nsCSSRules.h"
#include "mozilla/RestyleManager.h"
#include "nsLayoutUtils.h"
#include "nsIFrame.h"
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -7,17 +7,17 @@
#ifndef nsTransitionManager_h_
#define nsTransitionManager_h_
#include "mozilla/ContentEvents.h"
#include "mozilla/EffectCompositor.h" // For EffectCompositor::CascadeLevel
#include "mozilla/MemoryReporting.h"
#include "mozilla/dom/Animation.h"
-#include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
+#include "mozilla/dom/KeyframeEffectReadOnly.h"
#include "AnimationCommon.h"
#include "nsCSSProps.h"
class nsIGlobalObject;
class nsStyleContext;
class nsPresContext;
class nsCSSPropertyIDSet;