summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/animation/scroll_timeline.h
blob: 445af19f636f4c0d58d6e612108bfbc364d50bdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_SCROLL_TIMELINE_H_

#include "third_party/blink/renderer/core/animation/animation_timeline.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline_offset.h"
#include "third_party/blink/renderer/core/animation/timing.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"

namespace blink {

class DoubleOrScrollTimelineAutoKeyword;
class ScrollTimelineOptions;

// Implements the ScrollTimeline concept from the Scroll-linked Animations spec.
//
// A ScrollTimeline is a special form of AnimationTimeline whose time values are
// not determined by wall-clock time but instead the progress of scrolling in a
// scroll container. The user is able to specify which scroll container to
// track, the direction of scroll they care about, and various attributes to
// control the conversion of scroll amount to time output.
//
// Spec: https://wicg.github.io/scroll-animations/#scroll-timelines
class CORE_EXPORT ScrollTimeline : public AnimationTimeline {
  DEFINE_WRAPPERTYPEINFO();

 public:
  enum ScrollDirection {
    Block,
    Inline,
    Horizontal,
    Vertical,
  };

  static ScrollTimeline* Create(Document&,
                                ScrollTimelineOptions*,
                                ExceptionState&);

  ScrollTimeline(Document*,
                 Element*,
                 ScrollDirection,
                 HeapVector<Member<ScrollTimelineOffset>>,
                 base::Optional<double>);

  bool IsScrollTimeline() const override { return true; }
  // ScrollTimeline is not active if scrollSource is null, does not currently
  // have a CSS layout box, or if its layout box is not a scroll container.
  // https://github.com/WICG/scroll-animations/issues/31
  bool IsActive() const override;
  base::Optional<base::TimeDelta> InitialStartTimeForAnimations() override;
  AnimationTimeDelta ZeroTime() override { return AnimationTimeDelta(); }

  void ServiceAnimations(TimingUpdateReason) override;
  void ScheduleNextService() override;

  // IDL API implementation.
  Element* scrollSource() const;
  String orientation();
  // TODO(crbug.com/1094014): scrollOffsets will replace start and end
  // offsets once spec decision on multiple scroll offsets is finalized.
  // https://github.com/w3c/csswg-drafts/issues/4912
  void startScrollOffset(ScrollTimelineOffsetValue& result) const;
  void endScrollOffset(ScrollTimelineOffsetValue& result) const;
  const HeapVector<ScrollTimelineOffsetValue> scrollOffsets() const;

  void currentTime(CSSNumberish&) override;
  void duration(CSSNumberish&) override;
  void timeRange(DoubleOrScrollTimelineAutoKeyword&);

  // Returns the Node that should actually have the ScrollableArea (if one
  // exists). This can differ from |scrollSource| when |scroll_source_| is the
  // Document's scrollingElement, and it may be null if the document was
  // removed before the ScrollTimeline was created.
  Node* ResolvedScrollSource() const { return resolved_scroll_source_; }

  // Return the latest resolved scroll offsets. This will be empty when
  // timeline is inactive.
  const std::vector<double> GetResolvedScrollOffsets() const;

  ScrollDirection GetOrientation() const { return orientation_; }

  void GetCurrentAndMaxOffset(const LayoutBox*,
                              double& current_offset,
                              double& max_offset) const;
  // Invalidates scroll timeline as a result of scroller properties change.
  // This may lead the timeline to request a new animation frame.
  virtual void Invalidate();

  // Mark every effect target of every Animation attached to this timeline
  // for style recalc.
  void InvalidateEffectTargetStyle();

  // See DocumentAnimations::ValidateTimelines
  void ValidateState();

  CompositorAnimationTimeline* EnsureCompositorTimeline() override;
  void UpdateCompositorTimeline() override;

  // TODO(crbug.com/896249): These methods are temporary and currently required
  // to support worklet animations. Once worklet animations become animations
  // these methods will not be longer needed. They are used to keep track of
  // number of worklet animations attached to the scroll timeline for updating
  // compositing state.
  void WorkletAnimationAttached();
  void WorkletAnimationDetached();

  void AnimationAttached(Animation*) override;
  void AnimationDetached(Animation*) override;

  void Trace(Visitor*) const override;

  static bool HasActiveScrollTimeline(Node* node);
  // Invalidates scroll timelines with a given scroller node.
  // Called when scroller properties, affecting scroll timeline state, change.
  // These properties are scroller offset, content size, viewport size,
  // overflow, adding and removal of scrollable area.
  static void Invalidate(Node* node);

 protected:
  PhaseAndTime CurrentPhaseAndTime() override;
  double GetTimeRange() const { return time_range_ ? time_range_.value() : 0; }
  bool ScrollOffsetsEqual(
      const HeapVector<Member<ScrollTimelineOffset>>& other) const;
  size_t AttachedAnimationsCount() const { return scroll_animations_.size(); }

 private:
  FRIEND_TEST_ALL_PREFIXES(ScrollTimelineTest, MultipleScrollOffsetsClamping);
  // https://wicg.github.io/scroll-animations/#avoiding-cycles
  // Snapshots scroll timeline current time and phase.
  // Called once per animation frame.
  void SnapshotState();
  bool ComputeIsActive() const;
  PhaseAndTime ComputeCurrentPhaseAndTime() const;

  // Resolve scroll offsets The resolution process turns length-based values
  // into concrete length values resolving percentages and zoom factor. For
  // element-based values it computes the corresponding length value that maps
  // to the particular element intersection. See
  // |ScrollTimelineOffset::ResolveOffset()| for more details.
  bool ResolveScrollOffsets(WTF::Vector<double>& resolved_offsets) const;

  struct TimelineState {
    TimelinePhase phase;
    base::Optional<base::TimeDelta> current_time;
    // The resolved version of scroll offset. The vector is empty
    // when timeline is inactive (e.g., when source does not overflow).
    WTF::Vector<double> scroll_offsets;

    bool operator==(const TimelineState& other) const {
      return phase == other.phase && current_time == other.current_time &&
             scroll_offsets == other.scroll_offsets;
    }
  };

  TimelineState ComputeTimelineState() const;
  ScrollTimelineOffset* StartScrollOffset() const;
  ScrollTimelineOffset* EndScrollOffset() const;

  // Use time_check true to request next service if time has changed.
  // false - regardless of time change.
  void ScheduleNextServiceInternal(bool time_check);

  // Use |scroll_source_| only to implement the web-exposed API but use
  // resolved_scroll_source_ to actually access the scroll related properties.
  Member<Element> scroll_source_;
  Member<Node> resolved_scroll_source_;
  ScrollDirection orientation_;
  HeapVector<Member<ScrollTimelineOffset>> scroll_offsets_;

  base::Optional<double> time_range_;

  // Snapshotted value produced by the last SnapshotState call.
  TimelineState timeline_state_snapshotted_;

  // The only purpose of scroll_animations_ is keeping strong references to
  // attached animations. This is required to keep attached animations alive
  // as long as the timeline is alive. Scroll timeline is alive as long as its
  // scroller is alive.
  HeapHashSet<Member<Animation>> scroll_animations_;
};

template <>
struct DowncastTraits<ScrollTimeline> {
  static bool AllowFrom(const AnimationTimeline& value) {
    return value.IsScrollTimeline();
  }
};

}  // namespace blink

#endif