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
|