tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

KeyframeEffect.h (22623B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_KeyframeEffect_h
      8 #define mozilla_dom_KeyframeEffect_h
      9 
     10 #include "NonCustomCSSPropertyId.h"
     11 #include "mozilla/AnimatedPropertyIDSet.h"
     12 #include "mozilla/AnimationPerformanceWarning.h"
     13 #include "mozilla/AnimationPropertySegment.h"
     14 #include "mozilla/AnimationTarget.h"
     15 #include "mozilla/CSSPropertyId.h"
     16 #include "mozilla/EffectCompositor.h"
     17 #include "mozilla/Keyframe.h"
     18 #include "mozilla/KeyframeEffectParams.h"
     19 #include "mozilla/PostRestyleMode.h"
     20 #include "nsCSSPropertyIDSet.h"
     21 #include "nsCSSValue.h"
     22 #include "nsChangeHint.h"
     23 #include "nsCycleCollectionParticipant.h"
     24 #include "nsRefPtrHashtable.h"
     25 #include "nsTArray.h"
     26 #include "nsWrapperCache.h"
     27 // StyleLockedDeclarationBlock and associated RefPtrTraits
     28 #include "mozilla/ServoBindingTypes.h"
     29 #include "mozilla/StyleAnimationValue.h"
     30 #include "mozilla/dom/AnimationEffect.h"
     31 #include "mozilla/dom/BindingDeclarations.h"
     32 
     33 struct JSContext;
     34 class JSObject;
     35 class nsIContent;
     36 class nsIFrame;
     37 
     38 namespace mozilla {
     39 
     40 class AnimValuesStyleRule;
     41 class ErrorResult;
     42 struct AnimationRule;
     43 struct TimingParams;
     44 class EffectSet;
     45 class ComputedStyle;
     46 class PresShell;
     47 
     48 namespace dom {
     49 class Element;
     50 class GlobalObject;
     51 class UnrestrictedDoubleOrKeyframeAnimationOptions;
     52 class UnrestrictedDoubleOrKeyframeEffectOptions;
     53 enum class IterationCompositeOperation : uint8_t;
     54 enum class CompositeOperation : uint8_t;
     55 struct AnimationPropertyDetails;
     56 }  // namespace dom
     57 
     58 struct AnimationProperty {
     59  CSSPropertyId mProperty;
     60 
     61  // If true, the propery is currently being animated on the compositor.
     62  //
     63  // Note that when the owning Animation requests a non-throttled restyle, in
     64  // between calling RequestRestyle on its EffectCompositor and when the
     65  // restyle is performed, this member may temporarily become false even if
     66  // the animation remains on the layer after the restyle.
     67  //
     68  // **NOTE**: This member is not included when comparing AnimationProperty
     69  // objects for equality.
     70  bool mIsRunningOnCompositor = false;
     71 
     72  Maybe<AnimationPerformanceWarning> mPerformanceWarning;
     73 
     74  nsTArray<AnimationPropertySegment> mSegments;
     75 
     76  // The copy constructor/assignment doesn't copy mIsRunningOnCompositor and
     77  // mPerformanceWarning.
     78  AnimationProperty() : mProperty(eCSSProperty_UNKNOWN) {};
     79  AnimationProperty(const AnimationProperty& aOther)
     80      : mProperty(aOther.mProperty), mSegments(aOther.mSegments.Clone()) {}
     81  AnimationProperty& operator=(const AnimationProperty& aOther) {
     82    mProperty = aOther.mProperty;
     83    mSegments = aOther.mSegments.Clone();
     84    return *this;
     85  }
     86 
     87  // NOTE: This operator does *not* compare the mIsRunningOnCompositor member.
     88  // This is because AnimationProperty objects are compared when recreating
     89  // CSS animations to determine if mutation observer change records need to
     90  // be created or not. However, at the point when these objects are compared
     91  // the mIsRunningOnCompositor will not have been set on the new objects so
     92  // we ignore this member to avoid generating spurious change records.
     93  bool operator==(const AnimationProperty& aOther) const {
     94    return mProperty == aOther.mProperty && mSegments == aOther.mSegments;
     95  }
     96  bool operator!=(const AnimationProperty& aOther) const {
     97    return !(*this == aOther);
     98  }
     99 
    100  void SetPerformanceWarning(const AnimationPerformanceWarning& aWarning,
    101                             const dom::Element* aElement);
    102 };
    103 
    104 namespace dom {
    105 
    106 class Animation;
    107 class Document;
    108 
    109 class KeyframeEffect : public AnimationEffect {
    110 public:
    111  KeyframeEffect(Document* aDocument, OwningAnimationTarget&& aTarget,
    112                 TimingParams&& aTiming, const KeyframeEffectParams& aOptions);
    113 
    114  KeyframeEffect(Document* aDocument, OwningAnimationTarget&& aTarget,
    115                 const KeyframeEffect& aOther);
    116 
    117  NS_DECL_ISUPPORTS_INHERITED
    118  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffect,
    119                                                         AnimationEffect)
    120 
    121  virtual JSObject* WrapObject(JSContext* aCx,
    122                               JS::Handle<JSObject*> aGivenProto) override;
    123 
    124  KeyframeEffect* AsKeyframeEffect() override { return this; }
    125 
    126  bool IsValidTransition() const {
    127    return Properties().Length() == 1 &&
    128           Properties()[0].mSegments.Length() == 1;
    129  }
    130 
    131  // KeyframeEffect interface
    132  static already_AddRefed<KeyframeEffect> Constructor(
    133      const GlobalObject& aGlobal, Element* aTarget,
    134      JS::Handle<JSObject*> aKeyframes,
    135      const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
    136      ErrorResult& aRv);
    137 
    138  static already_AddRefed<KeyframeEffect> Constructor(
    139      const GlobalObject& aGlobal, KeyframeEffect& aSource, ErrorResult& aRv);
    140 
    141  // Variant of Constructor that accepts a KeyframeAnimationOptions object
    142  // for use with for Animatable.animate.
    143  // Not exposed to content.
    144  static already_AddRefed<KeyframeEffect> Constructor(
    145      const GlobalObject& aGlobal, Element* aTarget,
    146      JS::Handle<JSObject*> aKeyframes,
    147      const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
    148      ErrorResult& aRv);
    149 
    150  Element* GetTarget() const { return mTarget.mElement.get(); }
    151  NonOwningAnimationTarget GetAnimationTarget() const {
    152    return NonOwningAnimationTarget(mTarget.mElement, mTarget.mPseudoRequest);
    153  }
    154  void GetPseudoElement(nsAString& aRetVal) const {
    155    if (mTarget.mPseudoRequest.IsNotPseudo()) {
    156      SetDOMStringToNull(aRetVal);
    157      return;
    158    }
    159    aRetVal =
    160        nsCSSPseudoElements::PseudoRequestAsString(mTarget.mPseudoRequest);
    161  }
    162 
    163  // These two setters call GetTargetComputedStyle which is not safe to use when
    164  // we are in the middle of updating style. If we need to use this when
    165  // updating style, we should pass the ComputedStyle into this method and use
    166  // that to update the properties rather than calling
    167  // GetComputedStyle.
    168  void SetTarget(Element* aTarget) {
    169    UpdateTarget(aTarget, mTarget.mPseudoRequest);
    170  }
    171  void SetPseudoElement(const nsAString& aPseudoElement, ErrorResult& aRv);
    172 
    173  void GetKeyframes(JSContext* aCx, nsTArray<JSObject*>& aResult,
    174                    ErrorResult& aRv) const;
    175  void GetProperties(nsTArray<AnimationPropertyDetails>& aProperties,
    176                     ErrorResult& aRv) const;
    177 
    178  IterationCompositeOperation IterationComposite() const;
    179  void SetIterationComposite(
    180      const IterationCompositeOperation& aIterationComposite);
    181 
    182  CompositeOperation Composite() const;
    183  virtual void SetComposite(const CompositeOperation& aComposite);
    184  void SetCompositeFromStyle(const CompositeOperation& aComposite) {
    185    KeyframeEffect::SetComposite(aComposite);
    186  }
    187 
    188  void NotifySpecifiedTimingUpdated();
    189  void NotifyAnimationTimingUpdated(PostRestyleMode aPostRestyle);
    190  void RequestRestyle(EffectCompositor::RestyleType aRestyleType);
    191  void SetAnimation(Animation* aAnimation) override;
    192  virtual void SetKeyframes(JSContext* aContext,
    193                            JS::Handle<JSObject*> aKeyframes, ErrorResult& aRv);
    194  void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
    195                    const ComputedStyle* aStyle,
    196                    const AnimationTimeline* aTimeline);
    197 
    198  // Replace the start value of the transition. This is used for updating
    199  // transitions running on the compositor.
    200  void ReplaceTransitionStartValue(AnimationValue&& aStartValue);
    201 
    202  // Returns the set of properties affected by this effect regardless of
    203  // whether any of these properties is overridden by an !important rule.
    204  AnimatedPropertyIDSet GetPropertySet() const;
    205 
    206  // Returns true if the effect includes a property in |aPropertySet| regardless
    207  // of whether any property in the set is overridden by an !important rule.
    208  bool HasAnimationOfPropertySet(const nsCSSPropertyIDSet& aPropertySet) const {
    209    return GetPropertySet().Intersects(aPropertySet);
    210  }
    211 
    212  // GetEffectiveAnimationOfProperty returns AnimationProperty corresponding
    213  // to a given CSS property if the effect includes the property and the
    214  // property is not overridden by !important rules.
    215  // Also EffectiveAnimationOfProperty returns true under the same condition.
    216  //
    217  // |aEffect| should be the EffectSet containing this KeyframeEffect since
    218  // this function is typically called for all KeyframeEffects on an element
    219  // so that we can avoid multiple calls of EffectSet::GetEffect().
    220  //
    221  // Note that does not consider the interaction between related transform
    222  // properties where an !important rule on another transform property may
    223  // cause all transform properties to be run on the main thread. That check is
    224  // performed by GetPropertiesForCompositor.
    225  bool HasEffectiveAnimationOfProperty(const CSSPropertyId& aProperty,
    226                                       const EffectSet& aEffect) const {
    227    return GetEffectiveAnimationOfProperty(aProperty, aEffect) != nullptr;
    228  }
    229  const AnimationProperty* GetEffectiveAnimationOfProperty(
    230      const CSSPropertyId&, const EffectSet&) const;
    231 
    232  // Similar to HasEffectiveAnimationOfProperty, above, but for
    233  // an nsCSSPropertyIDSet. Returns true if this keyframe effect has at least
    234  // one property in |aPropertySet| that is not overridden by an !important
    235  // rule.
    236  //
    237  // Note that does not consider the interaction between related transform
    238  // properties where an !important rule on another transform property may
    239  // cause all transform properties to be run on the main thread. That check is
    240  // performed by GetPropertiesForCompositor.
    241  bool HasEffectiveAnimationOfPropertySet(
    242      const nsCSSPropertyIDSet& aPropertySet,
    243      const EffectSet& aEffectSet) const;
    244 
    245  // Returns all the effective animated CSS properties that can be animated on
    246  // the compositor and are not overridden by a higher cascade level.
    247  //
    248  // NOTE: This function is basically called for all KeyframeEffects on an
    249  // element thus it takes |aEffects| to avoid multiple calls of
    250  // EffectSet::GetEffect().
    251  //
    252  // NOTE(2): This function does NOT check that animations are permitted on
    253  // |aFrame|. It is the responsibility of the caller to first call
    254  // EffectCompositor::AllowCompositorAnimationsOnFrame for |aFrame|, or use
    255  // nsLayoutUtils::GetAnimationPropertiesForCompositor instead.
    256  nsCSSPropertyIDSet GetPropertiesForCompositor(EffectSet& aEffects,
    257                                                const nsIFrame* aFrame) const;
    258 
    259  const nsTArray<AnimationProperty>& Properties() const { return mProperties; }
    260 
    261  // Update |mProperties| by recalculating from |mKeyframes| using
    262  // |aComputedStyle| to resolve specified values.
    263  // Note: we use |aTimeline| to check if we need to ensure the base styles.
    264  // If it is nullptr, we use the timeline from |mAnimation|.
    265  void UpdateProperties(const ComputedStyle* aStyle,
    266                        const AnimationTimeline* aTimeline = nullptr);
    267 
    268  // Update various bits of state related to running ComposeStyle().
    269  // We need to update this outside ComposeStyle() because we should avoid
    270  // mutating any state in ComposeStyle() since it might be called during
    271  // parallel traversal.
    272  void WillComposeStyle();
    273 
    274  // Updates |aComposeResult| with the animation values produced by this
    275  // AnimationEffect for the current time except any properties contained
    276  // in |aPropertiesToSkip|.
    277  void ComposeStyle(
    278      StyleAnimationValueMap& aComposeResult,
    279      const InvertibleAnimatedPropertyIDSet& aPropertiesToSkip,
    280      EndpointBehavior aEndpointBehavior = EndpointBehavior::Exclusive);
    281 
    282  // Returns true if at least one property is being animated on compositor.
    283  bool IsRunningOnCompositor() const;
    284  void SetIsRunningOnCompositor(NonCustomCSSPropertyId aProperty,
    285                                bool aIsRunning);
    286  void SetIsRunningOnCompositor(const nsCSSPropertyIDSet& aPropertySet,
    287                                bool aIsRunning);
    288  void ResetIsRunningOnCompositor();
    289 
    290  void ResetPartialPrerendered();
    291 
    292  // Returns true if this effect, applied to |aFrame|, contains properties
    293  // that mean we shouldn't run transform compositor animations on this element.
    294  //
    295  // For example, if we have an animation of geometric properties like 'left'
    296  // and 'top' on an element, we force all 'transform' animations running at
    297  // the same time on the same element to run on the main thread.
    298  //
    299  // When returning true, |aPerformanceWarning| stores the reason why
    300  // we shouldn't run the transform animations.
    301  bool ShouldBlockAsyncTransformAnimations(
    302      const nsIFrame* aFrame, const nsCSSPropertyIDSet& aPropertySet,
    303      AnimationPerformanceWarning::Type& aPerformanceWarning /* out */) const;
    304  bool HasGeometricProperties() const;
    305  bool AffectsGeometry() const override {
    306    return mTarget && HasGeometricProperties();
    307  }
    308 
    309  Document* GetRenderedDocument() const;
    310  PresShell* GetPresShell() const;
    311 
    312  // Associates a warning with the animated property set on the specified frame
    313  // indicating why, for example, the property could not be animated on the
    314  // compositor. |aParams| and |aParamsLength| are optional parameters which
    315  // will be used to generate a localized message for devtools.
    316  void SetPerformanceWarning(const nsCSSPropertyIDSet& aPropertySet,
    317                             const AnimationPerformanceWarning& aWarning);
    318 
    319  // Cumulative change hint on each segment for each property.
    320  // This is used for deciding the animation is paint-only.
    321  void CalculateCumulativeChangesForProperty(const AnimationProperty&);
    322 
    323  // Returns true if all of animation properties' change hints
    324  // can ignore painting if the animation is not visible.
    325  // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h
    326  // in detail which change hint can be ignored.
    327  bool CanIgnoreIfNotVisible() const;
    328 
    329  // Returns true if the effect is current state and has scale animation.
    330  // |aFrame| is used for calculation of scale values.
    331  bool ContainsAnimatedScale(const nsIFrame* aFrame) const;
    332 
    333  AnimationValue BaseStyle(const CSSPropertyId& aProperty) const {
    334    AnimationValue result;
    335    bool hasProperty = false;
    336    // We cannot use getters_AddRefs on StyleAnimationValue because it is
    337    // an incomplete type, so Get() doesn't work. Instead, use GetWeak, and
    338    // then assign the raw pointer to a RefPtr.
    339    result.mServo = mBaseValues.GetWeak(aProperty, &hasProperty);
    340    MOZ_ASSERT(hasProperty || result.IsNull());
    341    return result;
    342  }
    343 
    344  void UpdateBaseStyle(const ComputedStyle* aStyle);
    345 
    346  enum class MatchForCompositor {
    347    // This animation matches and should run on the compositor if possible.
    348    Yes,
    349    // This (not currently playing) animation matches and can be run on the
    350    // compositor if there are other animations for this property that return
    351    // 'Yes'.
    352    IfNeeded,
    353    // This animation does not match or can't be run on the compositor.
    354    No,
    355    // This animation does not match or can't be run on the compositor and,
    356    // furthermore, its presence means we should not run any animations for this
    357    // property on the compositor.
    358    NoAndBlockThisProperty
    359  };
    360 
    361  MatchForCompositor IsMatchForCompositor(
    362      const nsCSSPropertyIDSet& aPropertySet, const nsIFrame* aFrame,
    363      const EffectSet& aEffects,
    364      AnimationPerformanceWarning::Type& aPerformanceWarning /* out */) const;
    365 
    366  static bool HasComputedTimingChanged(
    367      const ComputedTiming& aComputedTiming,
    368      IterationCompositeOperation aIterationComposite,
    369      const Nullable<double>& aProgressOnLastCompose,
    370      uint64_t aCurrentIterationOnLastCompose);
    371 
    372  bool HasOpacityChange() const { return mCumulativeChanges.mOpacity; }
    373 
    374 protected:
    375  ~KeyframeEffect() override = default;
    376 
    377  template <class OptionsType>
    378  static already_AddRefed<KeyframeEffect> ConstructKeyframeEffect(
    379      const GlobalObject& aGlobal, Element* aTarget,
    380      JS::Handle<JSObject*> aKeyframes, const OptionsType& aOptions,
    381      ErrorResult& aRv);
    382 
    383  // Build properties by recalculating from |mKeyframes| using |aComputedStyle|
    384  // to resolve specified values. This function also applies paced spacing if
    385  // needed.
    386  nsTArray<AnimationProperty> BuildProperties(const ComputedStyle* aStyle);
    387 
    388  // Helper for SetTarget() and SetPseudoElement().
    389  void UpdateTarget(Element* aElement,
    390                    const PseudoStyleRequest& aPseudoRequest);
    391 
    392  // This effect is registered with its target element so long as:
    393  //
    394  // (a) It has a target element, and
    395  // (b) It is "relevant" (i.e. yet to finish but not idle, or finished but
    396  //     filling forwards)
    397  //
    398  // As a result, we need to make sure this gets called whenever anything
    399  // changes with regards to this effects's timing including changes to the
    400  // owning Animation's timing.
    401  void UpdateTargetRegistration();
    402 
    403  // Remove the current effect target from its EffectSet.
    404  void UnregisterTarget();
    405 
    406  // Looks up the ComputedStyle associated with the target element, if any.
    407  // We need to be careful to *not* call this when we are updating the style
    408  // context. That's because calling GetComputedStyle when we are in the process
    409  // of building a ComputedStyle may trigger various forms of infinite
    410  // recursion.
    411  enum class Flush {
    412    Style,
    413    None,
    414  };
    415  already_AddRefed<const ComputedStyle> GetTargetComputedStyle(Flush) const;
    416 
    417  // A wrapper for marking cascade update according to the current
    418  // target and its effectSet.
    419  void MarkCascadeNeedsUpdate();
    420 
    421  void EnsureBaseStyles(const ComputedStyle* aComputedValues,
    422                        const nsTArray<AnimationProperty>& aProperties,
    423                        const AnimationTimeline* aTimeline,
    424                        bool* aBaseStylesChanged);
    425  void EnsureBaseStyle(const AnimationProperty& aProperty,
    426                       nsPresContext* aPresContext,
    427                       const ComputedStyle* aComputedValues,
    428                       const AnimationTimeline* aTimeline,
    429                       RefPtr<const ComputedStyle>& aBaseComputedValues);
    430 
    431  OwningAnimationTarget mTarget;
    432 
    433  KeyframeEffectParams mEffectOptions;
    434 
    435  // The specified keyframes.
    436  nsTArray<Keyframe> mKeyframes;
    437 
    438  // A set of per-property value arrays, derived from |mKeyframes|.
    439  nsTArray<AnimationProperty> mProperties;
    440 
    441  // The computed progress last time we composed the style rule. This is
    442  // used to detect when the progress is not changing (e.g. due to a step
    443  // timing function) so we can avoid unnecessary style updates.
    444  Nullable<double> mProgressOnLastCompose;
    445 
    446  // The purpose of this value is the same as mProgressOnLastCompose but
    447  // this is used to detect when the current iteration is not changing
    448  // in the case when iterationComposite is accumulate.
    449  uint64_t mCurrentIterationOnLastCompose = 0;
    450 
    451  // We need to track when we go to or from being "in effect" since
    452  // we need to re-evaluate the cascade of animations when that changes.
    453  bool mInEffectOnLastAnimationTimingUpdate = false;
    454 
    455  // True if this effect is in the EffectSet for its target element. This is
    456  // used as an optimization to avoid unnecessary hashmap lookups on the
    457  // EffectSet.
    458  bool mInEffectSet = false;
    459 
    460  // The non-animated values for properties in this effect that contain at
    461  // least one animation value that is composited with the underlying value
    462  // (i.e. it uses the additive or accumulate composite mode).
    463  using BaseValuesHashmap =
    464      nsRefPtrHashtable<nsGenericHashKey<CSSPropertyId>, StyleAnimationValue>;
    465  BaseValuesHashmap mBaseValues;
    466 
    467 private:
    468  // The cumulative changes of all the animation segments.
    469  struct CumulativeChanges {
    470    // Whether the opacity property is changing.
    471    bool mOpacity : 1;
    472    // Whether the visibility property is changing.
    473    bool mVisibility : 1;
    474    // Whether layout is changing.
    475    bool mLayout : 1;
    476    // Whether overflow is changing.
    477    bool mOverflow : 1;
    478    // True if there is any current-color for background color.
    479    bool mHasBackgroundColorCurrentColor : 1;
    480 
    481    CumulativeChanges()
    482        : mOpacity(false),
    483          mVisibility(false),
    484          mLayout(false),
    485          mOverflow(false),
    486          mHasBackgroundColorCurrentColor(false) {}
    487  };
    488  CumulativeChanges mCumulativeChanges;
    489 
    490  void ComposeStyleRule(StyleAnimationValueMap& aAnimationValues,
    491                        const AnimationProperty& aProperty,
    492                        const AnimationPropertySegment& aSegment,
    493                        const ComputedTiming& aComputedTiming);
    494 
    495  already_AddRefed<const ComputedStyle> CreateComputedStyleForAnimationValue(
    496      NonCustomCSSPropertyId aProperty, const AnimationValue& aValue,
    497      nsPresContext* aPresContext, const ComputedStyle* aBaseComputedStyle);
    498 
    499  // Return the primary frame for the target (pseudo-)element.
    500  nsIFrame* GetPrimaryFrame() const;
    501  // Returns the frame which is used for styling.
    502  nsIFrame* GetStyleFrame() const;
    503 
    504  bool CanThrottle() const;
    505  bool CanThrottleOverflowChanges(const nsIFrame& aFrame) const;
    506  bool CanThrottleOverflowChangesInScrollable(nsIFrame& aFrame) const;
    507  bool CanThrottleIfNotVisible(nsIFrame& aFrame) const;
    508 
    509  // Returns true if the computedTiming has changed since the last
    510  // composition.
    511  bool HasComputedTimingChanged() const;
    512 
    513  // Returns true unless Gecko limitations prevent performing transform
    514  // animations for |aFrame|. When returning true, the reason for the
    515  // limitation is stored in |aOutPerformanceWarning|.
    516  static bool CanAnimateTransformOnCompositor(
    517      const nsIFrame* aFrame,
    518      AnimationPerformanceWarning::Type& aPerformanceWarning /* out */);
    519  static bool IsGeometricProperty(const NonCustomCSSPropertyId aProperty);
    520 
    521  static const TimeDuration OverflowRegionRefreshInterval();
    522 
    523  void UpdateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
    524 
    525  // Returns true if this effect has properties that might affect the overflow
    526  // region.
    527  // This function is used for updating scroll bars or notifying intersection
    528  // observers reflected by the transform.
    529  bool HasPropertiesThatMightAffectOverflow() const {
    530    return mCumulativeChanges.mOverflow;
    531  }
    532 
    533  // Returns true if this effect causes visibility change.
    534  // (i.e. 'visibility: hidden' -> 'visibility: visible' and vice versa.)
    535  bool HasVisibilityChange() const { return mCumulativeChanges.mVisibility; }
    536 };
    537 
    538 }  // namespace dom
    539 }  // namespace mozilla
    540 
    541 #endif  // mozilla_dom_KeyframeEffect_h