Bug 1300045 part 2 - Split KeyframeEffect.cpp into KeyframeEffect{ReadOnly}.cpp r=hiro,smaug
authorBrian Birtles <birtles@gmail.com>
Sun, 04 Sep 2016 16:34:21 +0900
changeset 353919 0768e4f23ebf7ccfc7529498979e2a16dc2b39f4
parent 353918 8739a7982cee37f5443deb14844d38b5164d14df
child 353920 ce2a0cbdb4e80f88c9a12f63dcb49176525d3dd2
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershiro, smaug
bugs1300045
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1300045 part 2 - Split KeyframeEffect.cpp into KeyframeEffect{ReadOnly}.cpp r=hiro,smaug 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;