Bug 1300045 part 2 - Split KeyframeEffect.cpp into KeyframeEffect{ReadOnly}.cpp draft
authorBrian Birtles <birtles@gmail.com>
Sun, 04 Sep 2016 16:34:21 +0900
changeset 409689 de4887928f1092f8c352b698c94ce914285ca632
parent 409688 b6d80ae5efe2c168126843f901b2b38c86410753
child 530379 635a77f9077c54de8ee12ab94ae1318f67bcd34d
push id28510
push userbbirtles@mozilla.com
push dateSun, 04 Sep 2016 07:36:02 +0000
bugs1300045
milestone51.0a1
Bug 1300045 part 2 - Split KeyframeEffect.cpp into KeyframeEffect{ReadOnly}.cpp MozReview-Commit-ID: DdBEicunApv
dom/animation/Animation.h
dom/animation/AnimationEffectTiming.cpp
dom/animation/AnimationEffectTiming.h
dom/animation/EffectCompositor.cpp
dom/animation/EffectSet.h
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffect.h
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
dom/animation/KeyframeUtils.cpp
dom/animation/moz.build
dom/base/Element.cpp
dom/base/nsDOMMutationObserver.cpp
dom/base/nsNodeUtils.cpp
dom/webidl/KeyframeEffect.webidl
gfx/layers/Layers.cpp
gfx/layers/composite/AsyncCompositionManager.cpp
layout/base/ActiveLayerTracker.cpp
layout/base/nsDisplayList.cpp
layout/base/nsLayoutUtils.cpp
layout/style/AnimationCommon.cpp
layout/style/nsAnimationManager.cpp
layout/style/nsTransitionManager.h
--- 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;