tor-browser

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

CSSAnimation.h (9548B)


      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
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_dom_CSSAnimation_h
      8 #define mozilla_dom_CSSAnimation_h
      9 
     10 #include "AnimationCommon.h"
     11 #include "mozilla/StyleAnimationValue.h"
     12 #include "mozilla/dom/Animation.h"
     13 #include "mozilla/dom/KeyframeEffect.h"
     14 #include "mozilla/dom/MutationObservers.h"
     15 
     16 namespace mozilla {
     17 // Properties of CSS Animations that can be overridden by the Web Animations API
     18 // in a manner that means we should ignore subsequent changes to markup for that
     19 // property.
     20 enum class CSSAnimationProperties {
     21  None = 0,
     22  Keyframes = 1 << 0,
     23  Duration = 1 << 1,
     24  IterationCount = 1 << 2,
     25  Direction = 1 << 3,
     26  Delay = 1 << 4,
     27  FillMode = 1 << 5,
     28  Composition = 1 << 6,
     29  Effect = Keyframes | Duration | IterationCount | Direction | Delay |
     30           FillMode | Composition,
     31  PlayState = 1 << 7,
     32 };
     33 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CSSAnimationProperties)
     34 
     35 namespace dom {
     36 
     37 class CSSAnimation final : public Animation {
     38 public:
     39  explicit CSSAnimation(nsIGlobalObject* aGlobal, nsAtom* aAnimationName)
     40      : dom::Animation(aGlobal),
     41        mAnimationName(aAnimationName),
     42        mNeedsNewAnimationIndexWhenRun(false),
     43        mPreviousPhase(ComputedTiming::AnimationPhase::Idle),
     44        mPreviousIteration(0) {
     45    // We might need to drop this assertion once we add a script-accessible
     46    // constructor but for animations generated from CSS markup the
     47    // animation-name should never be empty.
     48    MOZ_ASSERT(mAnimationName != nsGkAtoms::_empty,
     49               "animation-name should not be 'none'");
     50  }
     51 
     52  JSObject* WrapObject(JSContext* aCx,
     53                       JS::Handle<JSObject*> aGivenProto) override;
     54 
     55  CSSAnimation* AsCSSAnimation() override { return this; }
     56  const CSSAnimation* AsCSSAnimation() const override { return this; }
     57 
     58  // CSSAnimation interface
     59  void GetAnimationName(nsString& aRetVal) const {
     60    mAnimationName->ToString(aRetVal);
     61  }
     62 
     63  nsAtom* AnimationName() const { return mAnimationName; }
     64 
     65  // Animation interface overrides
     66  void SetEffect(AnimationEffect* aEffect) override;
     67  void SetStartTimeAsDouble(const Nullable<double>& aStartTime) override;
     68  Promise* GetReady(ErrorResult& aRv) override;
     69  void Reverse(ErrorResult& aRv) override;
     70 
     71  // NOTE: tabbrowser.xml currently relies on the fact that reading the
     72  // currentTime of a CSSAnimation does *not* flush style (whereas reading the
     73  // playState does). If CSS Animations 2 specifies that reading currentTime
     74  // also flushes style we will need to find another way to detect canceled
     75  // animations in tabbrowser.xml. On the other hand, if CSS Animations 2
     76  // specifies that reading playState does *not* flush style (and we drop the
     77  // following override), then we should update tabbrowser.xml to check
     78  // the playState instead.
     79  AnimationPlayState PlayStateFromJS() const override;
     80  bool PendingFromJS() const override;
     81  void PlayFromJS(ErrorResult& aRv) override;
     82  void PauseFromJS(ErrorResult& aRv) override;
     83 
     84  void PlayFromStyle();
     85  void PauseFromStyle();
     86  void CancelFromStyle(PostRestyleMode aPostRestyle) {
     87    Animation::Cancel(aPostRestyle);
     88 
     89    // When an animation is disassociated with style it enters an odd state
     90    // where its composite order is undefined until it first transitions
     91    // out of the idle state.
     92    //
     93    // Even if the composite order isn't defined we don't want it to be random
     94    // in case we need to determine the order to dispatch events associated
     95    // with an animation in this state. To solve this we treat the animation as
     96    // if it had been added to the end of the global animation list so that
     97    // its sort order is defined. We'll update this index again once the
     98    // animation leaves the idle state.
     99    //
    100    // Note: We have to update |mAnimationIndex| after calling
    101    // Animation::Cancel(), which enqueues animationcancel event, to make sure
    102    // we have the correct |mAnimationIndex| in AnimationEventInfo.
    103    mAnimationIndex = sNextAnimationIndex++;
    104    mNeedsNewAnimationIndexWhenRun = true;
    105 
    106    // We need to do this *after* calling Cancel() since
    107    // Cancel() might synchronously trigger a cancel event for which
    108    // we need an owning element to target the event at.
    109    mOwningElement = OwningElementRef();
    110  }
    111 
    112  void Tick(TickState&) override;
    113  void QueueEvents(
    114      const StickyTimeDuration& aActiveTime = StickyTimeDuration());
    115 
    116  int32_t CompareCompositeOrder(const CSSAnimation& aOther,
    117                                nsContentUtils::NodeIndexCache&) const;
    118 
    119  void SetAnimationIndex(uint64_t aIndex) {
    120    MOZ_ASSERT(IsTiedToMarkup());
    121    if (IsRelevant() && mAnimationIndex != aIndex) {
    122      MutationObservers::NotifyAnimationChanged(this);
    123      PostUpdate();
    124    }
    125    mAnimationIndex = aIndex;
    126  }
    127 
    128  // Sets the owning element which is used for determining the composite
    129  // order of CSSAnimation objects generated from CSS markup.
    130  //
    131  // @see mOwningElement
    132  void SetOwningElement(const OwningElementRef& aElement) {
    133    mOwningElement = aElement;
    134  }
    135  // True for animations that are generated from CSS markup and continue to
    136  // reflect changes to that markup.
    137  bool IsTiedToMarkup() const { return mOwningElement.IsSet(); }
    138 
    139  void MaybeQueueCancelEvent(const StickyTimeDuration& aActiveTime) override {
    140    QueueEvents(aActiveTime);
    141  }
    142 
    143  CSSAnimationProperties GetOverriddenProperties() const {
    144    return mOverriddenProperties;
    145  }
    146  void AddOverriddenProperties(CSSAnimationProperties aProperties) {
    147    mOverriddenProperties |= aProperties;
    148  }
    149 
    150 protected:
    151  virtual ~CSSAnimation() {
    152    MOZ_ASSERT(!mOwningElement.IsSet(),
    153               "Owning element should be cleared "
    154               "before a CSS animation is destroyed");
    155  }
    156 
    157  // Animation overrides
    158  void UpdateTiming(SeekFlag aSeekFlag,
    159                    SyncNotifyFlag aSyncNotifyFlag) override;
    160 
    161  // Returns the duration from the start of the animation's source effect's
    162  // active interval to the point where the animation actually begins playback.
    163  // This is zero unless the animation's source effect has a negative delay in
    164  // which case it is the absolute value of that delay.
    165  // This is used for setting the elapsedTime member of CSS AnimationEvents.
    166  TimeDuration InitialAdvance() const {
    167    return mEffect ? std::max(TimeDuration(),
    168                              mEffect->NormalizedTiming().Delay() * -1)
    169                   : TimeDuration();
    170  }
    171 
    172  RefPtr<nsAtom> mAnimationName;
    173 
    174  // The (pseudo-)element whose computed animation-name refers to this
    175  // animation (if any).
    176  //
    177  // This is used for determining the relative composite order of animations
    178  // generated from CSS markup.
    179  //
    180  // Typically this will be the same as the target element of the keyframe
    181  // effect associated with this animation. However, it can differ in the
    182  // following circumstances:
    183  //
    184  // a) If script removes or replaces the effect of this animation,
    185  // b) If this animation is cancelled (e.g. by updating the
    186  //    animation-name property or removing the owning element from the
    187  //    document),
    188  // c) If this object is generated from script using the CSSAnimation
    189  //    constructor.
    190  //
    191  // For (b) and (c) the owning element will return !IsSet().
    192  OwningElementRef mOwningElement;
    193 
    194  // When true, indicates that when this animation next leaves the idle state,
    195  // its animation index should be updated.
    196  bool mNeedsNewAnimationIndexWhenRun;
    197 
    198  // Phase and current iteration from the previous time we queued events.
    199  // This is used to determine what new events to dispatch.
    200  ComputedTiming::AnimationPhase mPreviousPhase;
    201  uint64_t mPreviousIteration;
    202 
    203  // Properties that would normally be defined by the cascade but which have
    204  // since been explicitly set via the Web Animations API.
    205  CSSAnimationProperties mOverriddenProperties = CSSAnimationProperties::None;
    206 };
    207 
    208 // A subclass of KeyframeEffect that reports when specific properties have been
    209 // overridden via the Web Animations API.
    210 class CSSAnimationKeyframeEffect : public KeyframeEffect {
    211 public:
    212  CSSAnimationKeyframeEffect(Document* aDocument,
    213                             OwningAnimationTarget&& aTarget,
    214                             TimingParams&& aTiming,
    215                             const KeyframeEffectParams& aOptions)
    216      : KeyframeEffect(aDocument, std::move(aTarget), std::move(aTiming),
    217                       aOptions) {}
    218 
    219  void GetTiming(EffectTiming& aRetVal) const override;
    220  void GetComputedTimingAsDict(ComputedEffectTiming& aRetVal) const override;
    221  void UpdateTiming(const OptionalEffectTiming& aTiming,
    222                    ErrorResult& aRv) override;
    223  void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
    224                    ErrorResult& aRv) override;
    225  void SetComposite(const CompositeOperation& aComposite) override;
    226 
    227 private:
    228  CSSAnimation* GetOwningCSSAnimation() {
    229    return mAnimation ? mAnimation->AsCSSAnimation() : nullptr;
    230  }
    231  const CSSAnimation* GetOwningCSSAnimation() const {
    232    return mAnimation ? mAnimation->AsCSSAnimation() : nullptr;
    233  }
    234 
    235  // Flushes styles if our owning animation is a CSSAnimation
    236  void MaybeFlushUnanimatedStyle() const;
    237 };
    238 
    239 }  // namespace dom
    240 
    241 }  // namespace mozilla
    242 
    243 #endif  // mozilla_dom_CSSAnimation_h