summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc184
1 files changed, 99 insertions, 85 deletions
diff --git a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
index 39d1891e984..526519ef69c 100644
--- a/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
+++ b/chromium/third_party/blink/renderer/core/animation/scroll_timeline.cc
@@ -4,7 +4,9 @@
#include "third_party/blink/renderer/core/animation/scroll_timeline.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_scroll_timeline_options.h"
+#include "third_party/blink/renderer/core/animation/scroll_timeline_offset.h"
#include "third_party/blink/renderer/core/animation/scroll_timeline_util.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
#include "third_party/blink/renderer/core/css/parser/css_parser_context.h"
@@ -16,6 +18,7 @@
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
+#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
namespace blink {
@@ -57,19 +60,20 @@ bool StringToScrollDirection(String scroll_direction,
return false;
}
-bool StringToScrollOffset(String scroll_offset,
- const CSSParserContext& context,
- CSSPrimitiveValue** result) {
- CSSTokenizer tokenizer(scroll_offset);
- const auto tokens = tokenizer.TokenizeToEOF();
- CSSParserTokenRange range(tokens);
- CSSValue* value = css_parsing_utils::ConsumeScrollOffset(range, context);
- if (!value)
- return false;
-
- // We support 'auto', but for simplicity just store it as nullptr.
- *result = DynamicTo<CSSPrimitiveValue>(value);
- return true;
+ScrollOrientation ToPhysicalScrollOrientation(
+ ScrollTimeline::ScrollDirection direction,
+ const LayoutBox& source_box) {
+ bool is_horizontal = source_box.IsHorizontalWritingMode();
+ switch (direction) {
+ case ScrollTimeline::Block:
+ return is_horizontal ? kVerticalScroll : kHorizontalScroll;
+ case ScrollTimeline::Inline:
+ return is_horizontal ? kHorizontalScroll : kVerticalScroll;
+ case ScrollTimeline::Horizontal:
+ return kHorizontalScroll;
+ case ScrollTimeline::Vertical:
+ return kVerticalScroll;
+ }
}
// Note that the resolution process may trigger document lifecycle to clean
@@ -103,17 +107,17 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
return nullptr;
}
- CSSPrimitiveValue* start_scroll_offset = nullptr;
- if (!StringToScrollOffset(options->startScrollOffset(), *context,
- &start_scroll_offset)) {
- exception_state.ThrowTypeError("Invalid startScrollOffset");
+ ScrollTimelineOffset* start_scroll_offset =
+ ScrollTimelineOffset::Create(options->startScrollOffset(), *context);
+ if (!start_scroll_offset) {
+ exception_state.ThrowTypeError("Invalid start offset.");
return nullptr;
}
- CSSPrimitiveValue* end_scroll_offset = nullptr;
- if (!StringToScrollOffset(options->endScrollOffset(), *context,
- &end_scroll_offset)) {
- exception_state.ThrowTypeError("Invalid endScrollOffset");
+ ScrollTimelineOffset* end_scroll_offset =
+ ScrollTimelineOffset::Create(options->endScrollOffset(), *context);
+ if (!end_scroll_offset) {
+ exception_state.ThrowTypeError("Invalid end offset");
return nullptr;
}
@@ -133,8 +137,8 @@ ScrollTimeline* ScrollTimeline::Create(Document& document,
ScrollTimeline::ScrollTimeline(Document* document,
Element* scroll_source,
ScrollDirection orientation,
- CSSPrimitiveValue* start_scroll_offset,
- CSSPrimitiveValue* end_scroll_offset,
+ ScrollTimelineOffset* start_scroll_offset,
+ ScrollTimelineOffset* end_scroll_offset,
double time_range)
: AnimationTimeline(document),
scroll_source_(scroll_source),
@@ -156,7 +160,7 @@ ScrollTimeline::ScrollTimeline(Document* document,
}
bool ScrollTimeline::IsActive() const {
- return phase_and_time_snapshotted_.phase != TimelinePhase::kInactive;
+ return timeline_state_snapshotted_.phase != TimelinePhase::kInactive;
}
void ScrollTimeline::Invalidate() {
@@ -171,17 +175,37 @@ bool ScrollTimeline::ComputeIsActive() const {
layout_box->GetScrollableArea();
}
+void ScrollTimeline::ResolveScrollOffsets(double* start_offset,
+ double* end_offset) const {
+ DCHECK(ComputeIsActive());
+ LayoutBox* layout_box = resolved_scroll_source_->GetLayoutBox();
+ DCHECK(layout_box);
+
+ double current_offset;
+ double max_offset;
+ GetCurrentAndMaxOffset(layout_box, current_offset, max_offset);
+
+ DCHECK(start_scroll_offset_ && end_scroll_offset_);
+ auto orientation = ToPhysicalScrollOrientation(orientation_, *layout_box);
+ *start_offset = start_scroll_offset_->ResolveOffset(
+ resolved_scroll_source_, orientation, max_offset, 0);
+
+ *end_offset = end_scroll_offset_->ResolveOffset(
+ resolved_scroll_source_, orientation, max_offset, max_offset);
+}
+
AnimationTimeline::PhaseAndTime ScrollTimeline::CurrentPhaseAndTime() {
- return phase_and_time_snapshotted_;
+ return {timeline_state_snapshotted_.phase,
+ timeline_state_snapshotted_.current_time};
}
-AnimationTimeline::PhaseAndTime ScrollTimeline::ComputeCurrentPhaseAndTime()
- const {
+ScrollTimeline::TimelineState ScrollTimeline::ComputeTimelineState() const {
// 1. If scroll timeline is inactive, return an unresolved time value.
// https://github.com/WICG/scroll-animations/issues/31
// https://wicg.github.io/scroll-animations/#current-time-algorithm
if (!ComputeIsActive()) {
- return {TimelinePhase::kInactive, /*current_time*/ base::nullopt};
+ return {TimelinePhase::kInactive, /*current_time*/ base::nullopt,
+ base::nullopt, base::nullopt};
}
LayoutBox* layout_box = resolved_scroll_source_->GetLayoutBox();
// 2. Otherwise, let current scroll offset be the current scroll offset of
@@ -191,10 +215,9 @@ AnimationTimeline::PhaseAndTime ScrollTimeline::ComputeCurrentPhaseAndTime()
double max_offset;
GetCurrentAndMaxOffset(layout_box, current_offset, max_offset);
- double resolved_start_scroll_offset = 0;
- double resolved_end_scroll_offset = max_offset;
- ResolveScrollStartAndEnd(layout_box, max_offset, resolved_start_scroll_offset,
- resolved_end_scroll_offset);
+ double start_offset;
+ double end_offset;
+ ResolveScrollOffsets(&start_offset, &end_offset);
// TODO(crbug.com/1060384): Once the spec has been updated to state what the
// expected result is when startScrollOffset >= endScrollOffset, we might need
@@ -202,25 +225,31 @@ AnimationTimeline::PhaseAndTime ScrollTimeline::ComputeCurrentPhaseAndTime()
// https://github.com/WICG/scroll-animations/issues/20
// 3. If current scroll offset is less than startScrollOffset:
- if (current_offset < resolved_start_scroll_offset) {
- return {TimelinePhase::kBefore, base::TimeDelta()};
+ if (current_offset < start_offset) {
+ return {TimelinePhase::kBefore, base::TimeDelta(), start_offset,
+ end_offset};
}
// 4. If current scroll offset is greater than or equal to endScrollOffset:
- if (current_offset >= resolved_end_scroll_offset) {
- return {TimelinePhase::kAfter,
- base::TimeDelta::FromMillisecondsD(time_range_)};
+ if (current_offset >= end_offset) {
+ // If end_offset is greater than or equal to the maximum scroll offset of
+ // scrollSource in orientation then return active phase, otherwise return
+ // after phase.
+ TimelinePhase phase = end_offset >= max_offset ? TimelinePhase::kActive
+ : TimelinePhase::kAfter;
+ return {phase, base::TimeDelta::FromMillisecondsD(time_range_),
+ start_offset, end_offset};
}
// 5. Return the result of evaluating the following expression:
// ((current scroll offset - startScrollOffset) /
// (endScrollOffset - startScrollOffset)) * effective time range
base::Optional<base::TimeDelta> calculated_current_time =
- base::TimeDelta::FromMillisecondsD(
- ((current_offset - resolved_start_scroll_offset) /
- (resolved_end_scroll_offset - resolved_start_scroll_offset)) *
- time_range_);
- return {TimelinePhase::kActive, calculated_current_time};
+ base::TimeDelta::FromMillisecondsD((current_offset - start_offset) /
+ (end_offset - start_offset) *
+ time_range_);
+ return {TimelinePhase::kActive, calculated_current_time, start_offset,
+ end_offset};
}
// Scroll-linked animations are initialized with the start time of zero.
@@ -233,18 +262,29 @@ void ScrollTimeline::ServiceAnimations(TimingUpdateReason reason) {
// Snapshot timeline state once at top of animation frame.
if (reason == kTimingUpdateForAnimationFrame)
SnapshotState();
+ // When scroll timeline goes from inactive to active the animations may need
+ // to be started and possibly composited.
+ bool was_active =
+ last_current_phase_and_time_ &&
+ last_current_phase_and_time_.value().phase == TimelinePhase::kActive;
+ if (!was_active && IsActive())
+ MarkAnimationsCompositorPending();
+
AnimationTimeline::ServiceAnimations(reason);
}
void ScrollTimeline::ScheduleNextService() {
if (AnimationsNeedingUpdateCount() == 0)
return;
- if (ComputeCurrentPhaseAndTime() != last_current_phase_and_time_)
+
+ auto state = ComputeTimelineState();
+ PhaseAndTime current_phase_and_time{state.phase, state.current_time};
+ if (current_phase_and_time != last_current_phase_and_time_)
ScheduleServiceOnNextFrame();
}
void ScrollTimeline::SnapshotState() {
- phase_and_time_snapshotted_ = ComputeCurrentPhaseAndTime();
+ timeline_state_snapshotted_ = ComputeTimelineState();
}
Element* ScrollTimeline::scrollSource() {
@@ -267,12 +307,19 @@ String ScrollTimeline::orientation() {
}
}
-String ScrollTimeline::startScrollOffset() {
- return start_scroll_offset_ ? start_scroll_offset_->CssText() : "auto";
+void ScrollTimeline::startScrollOffset(
+ StringOrScrollTimelineElementBasedOffset& out) const {
+ if (!start_scroll_offset_)
+ return;
+ out = start_scroll_offset_->ToStringOrScrollTimelineElementBasedOffset();
}
-String ScrollTimeline::endScrollOffset() {
- return end_scroll_offset_ ? end_scroll_offset_->CssText() : "auto";
+void ScrollTimeline::endScrollOffset(
+ StringOrScrollTimelineElementBasedOffset& out) const {
+ if (!end_scroll_offset_)
+ return;
+
+ out = end_scroll_offset_->ToStringOrScrollTimelineElementBasedOffset();
}
void ScrollTimeline::timeRange(DoubleOrScrollTimelineAutoKeyword& result) {
@@ -302,22 +349,13 @@ void ScrollTimeline::GetCurrentAndMaxOffset(const LayoutBox* layout_box,
ScrollOffset scroll_dimensions = scrollable_area->MaximumScrollOffset() -
scrollable_area->MinimumScrollOffset();
- bool is_horizontal = layout_box->IsHorizontalWritingMode();
- if (orientation_ == Block) {
- current_offset =
- is_horizontal ? scroll_offset.Height() : scroll_offset.Width();
- max_offset =
- is_horizontal ? scroll_dimensions.Height() : scroll_dimensions.Width();
- } else if (orientation_ == Inline) {
- current_offset =
- is_horizontal ? scroll_offset.Width() : scroll_offset.Height();
- max_offset =
- is_horizontal ? scroll_dimensions.Width() : scroll_dimensions.Height();
- } else if (orientation_ == Horizontal) {
+ auto physical_orientation =
+ ToPhysicalScrollOrientation(orientation_, *layout_box);
+
+ if (physical_orientation == kHorizontalScroll) {
current_offset = scroll_offset.Width();
max_offset = scroll_dimensions.Width();
} else {
- DCHECK(orientation_ == Vertical);
current_offset = scroll_offset.Height();
max_offset = scroll_dimensions.Height();
}
@@ -328,30 +366,6 @@ void ScrollTimeline::GetCurrentAndMaxOffset(const LayoutBox* layout_box,
current_offset = std::abs(current_offset);
}
-void ScrollTimeline::ResolveScrollStartAndEnd(
- const LayoutBox* layout_box,
- double max_offset,
- double& resolved_start_scroll_offset,
- double& resolved_end_scroll_offset) const {
- DCHECK(layout_box);
- const ComputedStyle& computed_style = layout_box->StyleRef();
- Document& document = layout_box->GetDocument();
- const ComputedStyle* root_style =
- document.documentElement()
- ? document.documentElement()->GetComputedStyle()
- : document.GetComputedStyle();
- CSSToLengthConversionData conversion_data = CSSToLengthConversionData(
- &computed_style, root_style, document.GetLayoutView(),
- computed_style.EffectiveZoom());
- if (start_scroll_offset_) {
- resolved_start_scroll_offset = FloatValueForLength(
- start_scroll_offset_->ConvertToLength(conversion_data), max_offset);
- }
- if (end_scroll_offset_) {
- resolved_end_scroll_offset = FloatValueForLength(
- end_scroll_offset_->ConvertToLength(conversion_data), max_offset);
- }
-}
void ScrollTimeline::WorkletAnimationAttached() {
if (!resolved_scroll_source_)