OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "core/animation/ScrollTimeline.h" | |
6 | |
7 #include "core/dom/ExceptionCode.h" | |
8 #include "core/layout/LayoutBox.h" | |
9 #include "core/paint/PaintLayerScrollableArea.h" | |
10 | |
11 namespace blink { | |
12 | |
13 namespace { | |
14 bool StringToScrollDirection(String scroll_direction, | |
15 ScrollTimeline::ScrollDirection& result) { | |
16 // TODO(smcgruer): Support 'auto' value. | |
17 if (scroll_direction == "block") { | |
18 result = ScrollTimeline::Block; | |
19 return true; | |
20 } | |
21 if (scroll_direction == "inline") { | |
22 result = ScrollTimeline::Inline; | |
23 return true; | |
24 } | |
25 return false; | |
26 } | |
27 } // namespace | |
28 | |
29 ScrollTimeline* ScrollTimeline::Create(Document& document, | |
30 ScrollTimelineOptions options, | |
31 ExceptionState& exception_state) { | |
32 Element* scroll_source = options.scrollSource() ? options.scrollSource() | |
33 : document.scrollingElement(); | |
34 | |
35 ScrollDirection orientation; | |
36 if (!StringToScrollDirection(options.orientation(), orientation)) { | |
37 exception_state.ThrowDOMException(kNotSupportedError, | |
38 "Invalid orientation"); | |
39 return nullptr; | |
40 } | |
41 | |
42 // TODO(smcgruer): Support 'auto' value. | |
43 if (options.timeRange().isScrollTimelineAutoKeyword()) { | |
44 exception_state.ThrowDOMException( | |
45 kNotSupportedError, "'auto' value for timeRange not yet supported"); | |
46 return nullptr; | |
47 } | |
48 | |
49 return new ScrollTimeline(document, scroll_source, orientation, | |
50 options.timeRange().getAsDouble()); | |
51 } | |
52 | |
53 ScrollTimeline::ScrollTimeline(const Document& document, | |
54 Element* scroll_source, | |
55 ScrollDirection orientation, | |
56 double time_range) | |
57 : scroll_source_(scroll_source), | |
58 orientation_(orientation), | |
59 time_range_(time_range) { | |
60 DCHECK(RuntimeEnabledFeatures::CompositorWorkerEnabled()); | |
61 } | |
62 | |
63 double ScrollTimeline::currentTime(bool& is_null) { | |
64 // 1. If scrollSource does not currently have a CSS layout box, or if its | |
65 // layout box is not a scroll container, return an unresolved time value. | |
66 LayoutBox* layout_box = scroll_source_->GetLayoutBox(); | |
67 if (!layout_box || !layout_box->HasOverflowClip()) { | |
68 is_null = false; | |
69 return std::numeric_limits<double>::quiet_NaN(); | |
70 } | |
71 | |
72 // 2. Otherwise, let current scroll offset be the current scroll offset of | |
73 // scrollSource in the direction specified by orientation. | |
74 | |
75 // Depending on the writing-mode and direction, the scroll origin shifts and | |
76 // the scroll offset may be negative. The easiest way to deal with this is to | |
77 // use only the magnitude of the scroll offset, and compare it to (max-offset | |
78 // - min_offset). | |
79 PaintLayerScrollableArea* scrollable_area = layout_box->GetScrollableArea(); | |
80 // Using the absolute value of the scroll offset only makes sense if either | |
81 // the max or min scroll offset for a given axis is 0. This should be | |
82 // guaranteed by the scroll origin code, but these DCHECKs ensure that. | |
83 DCHECK(scrollable_area->MaximumScrollOffset().Height() == 0 || | |
84 scrollable_area->MinimumScrollOffset().Height() == 0); | |
85 DCHECK(scrollable_area->MaximumScrollOffset().Width() == 0 || | |
86 scrollable_area->MinimumScrollOffset().Width() == 0); | |
87 ScrollOffset scroll_offset = scrollable_area->GetScrollOffset(); | |
88 ScrollOffset scroll_dimensions = scrollable_area->MaximumScrollOffset() - | |
89 scrollable_area->MinimumScrollOffset(); | |
90 | |
91 double current_offset; | |
92 double max_offset; | |
93 bool is_horizontal = layout_box->IsHorizontalWritingMode(); | |
94 if (orientation_ == Block) { | |
95 current_offset = | |
96 is_horizontal ? scroll_offset.Height() : scroll_offset.Width(); | |
97 max_offset = | |
98 is_horizontal ? scroll_dimensions.Height() : scroll_dimensions.Width(); | |
99 } else { | |
100 current_offset = | |
alancutter (OOO until 2018)
2017/07/04 04:13:41
Assert that orientation_ is Inline here to make th
smcgruer
2017/07/04 13:48:53
Done.
| |
101 is_horizontal ? scroll_offset.Width() : scroll_offset.Height(); | |
102 max_offset = | |
103 is_horizontal ? scroll_dimensions.Width() : scroll_dimensions.Height(); | |
104 } | |
105 | |
106 // 3. If current scroll offset is less than startScrollOffset, return an | |
107 // unresolved time value if fill is none or forwards, or 0 otherwise. | |
108 // TODO(smcgruer): Implement |startScrollOffset| and |fill|. | |
109 | |
110 // 4. If current scroll offset is greater than or equal to endScrollOffset, | |
111 // return an unresolved time value if fill is none or backwards, or the | |
112 // effective time range otherwise. | |
113 // TODO(smcgruer): Implement |endScrollOffset| and |fill|. | |
114 | |
115 // 5. Return the result of evaluating the following expression: | |
116 // ((current scroll offset - startScrollOffset) / | |
117 // (endScrollOffset - startScrollOffset)) * effective time range | |
118 | |
119 is_null = false; | |
120 return (std::abs(current_offset) / max_offset) * time_range_; | |
121 } | |
122 | |
123 Element* ScrollTimeline::scrollSource() { | |
124 return scroll_source_.Get(); | |
125 } | |
126 | |
127 String ScrollTimeline::orientation() { | |
128 switch (orientation_) { | |
129 case Block: | |
130 return "block"; | |
131 case Inline: | |
132 return "inline"; | |
133 default: | |
134 NOTREACHED(); | |
135 return ""; | |
136 } | |
137 } | |
138 | |
139 void ScrollTimeline::timeRange(DoubleOrScrollTimelineAutoKeyword& result) { | |
140 result.setDouble(time_range_); | |
141 } | |
142 | |
143 DEFINE_TRACE(ScrollTimeline) { | |
144 visitor->Trace(scroll_source_); | |
145 AnimationTimeline::Trace(visitor); | |
146 } | |
147 | |
148 } // namespace blink | |
OLD | NEW |