summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/animation/scroll_timeline_util.cc
blob: 714034716e188777b53375d4603c79a26b16575c (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
// Copyright 2018 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.

#include "third_party/blink/renderer/core/animation/scroll_timeline_util.h"

#include "third_party/blink/renderer/bindings/core/v8/double_or_scroll_timeline_auto_keyword.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_double_scrolltimelineautokeyword.h"
#include "third_party/blink/renderer/core/animation/animation_timeline.h"
#include "third_party/blink/renderer/core/animation/document_timeline.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"

namespace blink {

namespace scroll_timeline_util {

scoped_refptr<CompositorScrollTimeline> ToCompositorScrollTimeline(
    AnimationTimeline* timeline) {
  if (!timeline || IsA<DocumentTimeline>(timeline))
    return nullptr;

  auto* scroll_timeline = To<ScrollTimeline>(timeline);
  Node* scroll_source = scroll_timeline->ResolvedScrollSource();
  absl::optional<CompositorElementId> element_id =
      GetCompositorScrollElementId(scroll_source);

#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
  auto* time_range = scroll_timeline->timeRange();
  DCHECK(time_range);
#else   // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
  DoubleOrScrollTimelineAutoKeyword time_range;
  scroll_timeline->timeRange(time_range);
  // TODO(smcgruer): Handle 'auto' time range value.
  DCHECK(time_range.IsDouble());
#endif  // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)

  LayoutBox* box =
      scroll_timeline->IsActive() ? scroll_source->GetLayoutBox() : nullptr;

  CompositorScrollTimeline::ScrollDirection orientation = ConvertOrientation(
      scroll_timeline->GetOrientation(), box ? box->Style() : nullptr);

  return CompositorScrollTimeline::Create(
      element_id, orientation, scroll_timeline->GetResolvedScrollOffsets(),
#if defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
      time_range->GetAsDouble()
#else   // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
      time_range.GetAsDouble()
#endif  // defined(USE_BLINK_V8_BINDING_NEW_IDL_UNION)
  );
}

absl::optional<CompositorElementId> GetCompositorScrollElementId(
    const Node* node) {
  if (!node || !node->GetLayoutObject() ||
      !node->GetLayoutObject()->FirstFragment().PaintProperties()) {
    return absl::nullopt;
  }
  return CompositorElementIdFromUniqueObjectId(
      node->GetLayoutObject()->UniqueId(),
      CompositorElementIdNamespace::kScroll);
}

// The compositor does not know about writing modes, so we have to convert the
// web concepts of 'block' and 'inline' direction into absolute vertical or
// horizontal directions.
CompositorScrollTimeline::ScrollDirection ConvertOrientation(
    ScrollTimeline::ScrollDirection orientation,
    const ComputedStyle* style) {
  // Easy cases; physical is always physical.
  if (orientation == ScrollTimeline::Horizontal)
    return CompositorScrollTimeline::ScrollRight;
  if (orientation == ScrollTimeline::Vertical)
    return CompositorScrollTimeline::ScrollDown;

  // Harder cases; first work out which axis is which, and then for each check
  // which edge we start at.

  // writing-mode: horizontal-tb
  bool is_horizontal_writing_mode =
      style ? style->IsHorizontalWritingMode() : true;
  // writing-mode: vertical-lr
  bool is_flipped_lines_writing_mode =
      style ? style->IsFlippedLinesWritingMode() : false;
  // direction: ltr;
  bool is_ltr_direction = style ? style->IsLeftToRightDirection() : true;

  if (orientation == ScrollTimeline::Block) {
    if (is_horizontal_writing_mode) {
      // For horizontal writing mode, block is vertical. The starting edge is
      // always the top.
      return CompositorScrollTimeline::ScrollDown;
    }
    // For vertical writing mode, the block axis is horizontal. The starting
    // edge depends on if we are lr or rl.
    return is_flipped_lines_writing_mode ? CompositorScrollTimeline::ScrollRight
                                         : CompositorScrollTimeline::ScrollLeft;
  }

  DCHECK_EQ(orientation, ScrollTimeline::Inline);
  if (is_horizontal_writing_mode) {
    // For horizontal writing mode, inline is horizontal. The starting edge
    // depends on the directionality.
    return is_ltr_direction ? CompositorScrollTimeline::ScrollRight
                            : CompositorScrollTimeline::ScrollLeft;
  }
  // For vertical writing mode, inline is vertical. The starting edge still
  // depends on the directionality; whether it is vertical-lr or vertical-rl
  // does not matter.
  return is_ltr_direction ? CompositorScrollTimeline::ScrollDown
                          : CompositorScrollTimeline::ScrollUp;
}

double ComputeProgress(double current_offset,
                       const WTF::Vector<double>& resolved_offsets) {
  return cc::ComputeProgress<WTF::Vector<double>>(current_offset,
                                                  resolved_offsets);
}

}  // namespace scroll_timeline_util

}  // namespace blink