tor-browser

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

ScrollTimeline.h (8615B)


      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_ScrollTimeline_h
      8 #define mozilla_dom_ScrollTimeline_h
      9 
     10 #include "mozilla/LinkedList.h"
     11 #include "mozilla/ServoStyleConsts.h"
     12 #include "mozilla/WritingModes.h"
     13 #include "mozilla/dom/AnimationTimeline.h"
     14 
     15 #define PROGRESS_TIMELINE_DURATION_MILLISEC 100000
     16 
     17 namespace mozilla {
     18 class ScrollContainerFrame;
     19 class ElementAnimationData;
     20 struct NonOwningAnimationTarget;
     21 namespace dom {
     22 class Document;
     23 class Element;
     24 
     25 /**
     26 * Implementation notes
     27 * --------------------
     28 *
     29 * ScrollTimelines do not observe refreshes the way DocumentTimelines do.
     30 * This is because the refresh driver keeps ticking while it has registered
     31 * refresh observers. For a DocumentTimeline, it's appropriate to keep the
     32 * refresh driver ticking as long as there are active animations, since the
     33 * animations need to be sampled on every frame. Scroll-linked animations,
     34 * however, only need to be sampled when scrolling has occurred, so keeping
     35 * the refresh driver ticking is wasteful.
     36 *
     37 * As a result, we schedule an animation restyle when
     38 * 1) there are any scroll offsets updated (from APZ or script), via
     39 *    ScrollContainerFrame, or
     40 * 2) there are any possible scroll range updated during the frame reflow.
     41 *
     42 * -------------
     43 * | Animation |
     44 * -------------
     45 *   ^
     46 *   | Call Animation::Tick() if there are any scroll updates.
     47 *   |
     48 * ------------------
     49 * | ScrollTimeline |
     50 * ------------------
     51 *   ^
     52 *   | Try schedule the scroll-driven animations, if there are any scroll
     53 *   | offsets changed or the scroll range changed [1].
     54 *   |
     55 * ------------------------
     56 * | ScrollContainerFrame |
     57 * ------------------------
     58 *
     59 * [1] ScrollContainerFrame uses its associated dom::Element to lookup the
     60 *     ScrollTimelineSet, and iterates the set to schedule the animations
     61 *     linked to the ScrollTimelines.
     62 */
     63 class ScrollTimeline : public AnimationTimeline,
     64                       public LinkedListElement<ScrollTimeline> {
     65  template <typename T, typename... Args>
     66  friend already_AddRefed<T> mozilla::MakeAndAddRef(Args&&... aArgs);
     67 
     68 public:
     69  struct Scroller {
     70    // FIXME: Bug 1765211. Perhaps we only need root and a specific element.
     71    // This depends on how we fix this bug.
     72    enum class Type : uint8_t {
     73      Root,
     74      Nearest,
     75      Name,
     76      Self,
     77    };
     78    Type mType = Type::Root;
     79    RefPtr<Element> mElement;
     80    // FIXME: Bug 1928437. We have to update mPseudoType to use
     81    // PseudoStyleRequest.
     82    PseudoStyleType mPseudoType;
     83 
     84    static Scroller Root(Element* aDocumentElement) {
     85      return {Type::Root, aDocumentElement, PseudoStyleType::NotPseudo};
     86    }
     87 
     88    static Scroller Nearest(Element* aElement, PseudoStyleType aPseudoType) {
     89      return {Type::Nearest, aElement, aPseudoType};
     90    }
     91 
     92    static Scroller Named(Element* aElement, PseudoStyleType aPseudoType) {
     93      return {Type::Name, aElement, aPseudoType};
     94    }
     95 
     96    static Scroller Self(Element* aElement, PseudoStyleType aPseudoType) {
     97      return {Type::Self, aElement, aPseudoType};
     98    }
     99 
    100    explicit operator bool() const { return mElement; }
    101    bool operator==(const Scroller& aOther) const {
    102      return mType == aOther.mType && mElement == aOther.mElement &&
    103             mPseudoType == aOther.mPseudoType;
    104    }
    105  };
    106 
    107  static already_AddRefed<ScrollTimeline> MakeAnonymous(
    108      Document* aDocument, const NonOwningAnimationTarget& aTarget,
    109      StyleScrollAxis aAxis, StyleScroller aScroller);
    110 
    111  // Note: |aReferfenceElement| is used as the scroller which specifies
    112  // scroll-timeline-name property.
    113  static already_AddRefed<ScrollTimeline> MakeNamed(
    114      Document* aDocument, Element* aReferenceElement,
    115      const PseudoStyleRequest& aPseudoRequest,
    116      const StyleScrollTimeline& aStyleTimeline);
    117 
    118  bool operator==(const ScrollTimeline& aOther) const {
    119    return mDocument == aOther.mDocument && mSource == aOther.mSource &&
    120           mAxis == aOther.mAxis;
    121  }
    122 
    123  NS_DECL_ISUPPORTS_INHERITED
    124  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScrollTimeline, AnimationTimeline)
    125 
    126  JSObject* WrapObject(JSContext* aCx,
    127                       JS::Handle<JSObject*> aGivenProto) override {
    128    // FIXME: Bug 1676794: Implement ScrollTimeline interface.
    129    return nullptr;
    130  }
    131 
    132  // AnimationTimeline methods.
    133  Nullable<TimeDuration> GetCurrentTimeAsDuration() const override;
    134  bool TracksWallclockTime() const override { return false; }
    135  Nullable<TimeDuration> ToTimelineTime(
    136      const TimeStamp& aTimeStamp) const override {
    137    // It's unclear to us what should we do for this function now, so return
    138    // nullptr.
    139    return nullptr;
    140  }
    141  TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const override {
    142    // It's unclear to us what should we do for this function now, so return
    143    // zero time.
    144    return {};
    145  }
    146  Document* GetDocument() const override { return mDocument; }
    147  bool IsMonotonicallyIncreasing() const override { return false; }
    148  bool IsScrollTimeline() const override { return true; }
    149  const ScrollTimeline* AsScrollTimeline() const override { return this; }
    150  bool IsViewTimeline() const override { return false; }
    151 
    152  Nullable<TimeDuration> TimelineDuration() const override {
    153    // We are using this magic number for progress-based timeline duration
    154    // because we don't support percentage for duration.
    155    return TimeDuration::FromMilliseconds(PROGRESS_TIMELINE_DURATION_MILLISEC);
    156  }
    157 
    158  void WillRefresh();
    159 
    160  // If the source of a ScrollTimeline is an element whose principal box does
    161  // not exist or is not a scroll container, then its phase is the timeline
    162  // inactive phase. It is otherwise in the active phase. This returns true if
    163  // the timeline is in active phase.
    164  // https://drafts.csswg.org/web-animations-1/#inactive-timeline
    165  // Note: This function is called only for compositor animations, so we must
    166  // have the primary frame (principal box) for the source element if it exists.
    167  bool IsActive() const { return GetScrollContainerFrame(); }
    168 
    169  Element* SourceElement() const {
    170    MOZ_ASSERT(mSource);
    171    return mSource.mElement;
    172  }
    173 
    174  // A helper to get the physical orientation of this scroll-timeline.
    175  layers::ScrollDirection Axis() const;
    176 
    177  StyleOverflow SourceScrollStyle() const;
    178 
    179  bool APZIsActiveForSource() const;
    180 
    181  bool ScrollingDirectionIsAvailable() const;
    182 
    183  void ReplacePropertiesWith(const Element* aReferenceElement,
    184                             const PseudoStyleRequest& aPseudoRequest,
    185                             const StyleScrollTimeline& aNew);
    186 
    187  void NotifyAnimationUpdated(Animation& aAnimation) override;
    188 
    189  void NotifyAnimationContentVisibilityChanged(Animation* aAnimation,
    190                                               bool aIsVisible) override;
    191 
    192  void UpdateCachedCurrentTime();
    193 
    194 protected:
    195  virtual ~ScrollTimeline();
    196  ScrollTimeline() = delete;
    197  ScrollTimeline(Document* aDocument, const Scroller& aScroller,
    198                 StyleScrollAxis aAxis);
    199 
    200  struct ScrollOffsets {
    201    nscoord mStart = 0;
    202    nscoord mEnd = 0;
    203  };
    204  virtual Maybe<ScrollOffsets> ComputeOffsets(
    205      const ScrollContainerFrame* aScrollFrame,
    206      layers::ScrollDirection aOrientation) const;
    207 
    208  // Note: This function is required to be idempotent, as it can be called from
    209  // both cycleCollection::Unlink() and ~ScrollTimeline(). When modifying this
    210  // function, be sure to preserve this property.
    211  void Teardown() {
    212    if (isInList()) {
    213      remove();
    214    }
    215  }
    216 
    217  const ScrollContainerFrame* GetScrollContainerFrame() const;
    218 
    219  static std::pair<const Element*, PseudoStyleRequest> FindNearestScroller(
    220      Element* aSubject, const PseudoStyleRequest& aPseudoRequest);
    221 
    222  RefPtr<Document> mDocument;
    223 
    224  // FIXME: Bug 1765211: We may have to update the source element once the
    225  // overflow property of the scroll-container is updated when we are using
    226  // nearest scroller.
    227  Scroller mSource;
    228  StyleScrollAxis mAxis;
    229 
    230  struct CurrentTimeData {
    231    // The position of the scroller, and this may be negative for RTL or
    232    // sideways, e.g. the range of its value could be [0, -range]. The user
    233    // needs to take care of that.
    234    nscoord mPosition;
    235    ScrollOffsets mOffsets;
    236  };
    237  Maybe<CurrentTimeData> mCachedCurrentTime;
    238 };
    239 
    240 }  // namespace dom
    241 }  // namespace mozilla
    242 
    243 #endif  // mozilla_dom_ScrollTimeline_h