Index: third_party/WebKit/Source/core/animation/ScrollTimeline.cpp |
diff --git a/third_party/WebKit/Source/core/animation/ScrollTimeline.cpp b/third_party/WebKit/Source/core/animation/ScrollTimeline.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6ec16b952687af5e921aa767b69e9c1681f3e24e |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/animation/ScrollTimeline.cpp |
@@ -0,0 +1,175 @@ |
+// 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. |
+ |
+#include "core/animation/ScrollTimeline.h" |
+ |
+#include "core/dom/ExceptionCode.h" |
+#include "core/layout/LayoutBox.h" |
+#include "core/paint/PaintLayerScrollableArea.h" |
+ |
+namespace blink { |
+ |
+namespace { |
+bool StringToScrollDirection(String scroll_direction, |
+ ScrollTimeline::ScrollDirection* result) { |
+ if (scroll_direction == "auto") { |
+ *result = ScrollTimeline::Auto; |
+ return true; |
+ } |
+ if (scroll_direction == "block") { |
+ *result = ScrollTimeline::Block; |
+ return true; |
+ } |
+ if (scroll_direction == "inline") { |
+ *result = ScrollTimeline::Inline; |
+ return true; |
+ } |
+ return false; |
+} |
+} // namespace |
+ |
+ScrollTimeline* ScrollTimeline::Create(Document& document, |
+ ScrollTimelineOptions options, |
+ ExceptionState& exception_state) { |
+ Element* scroll_source = options.scrollSource() ? options.scrollSource() |
+ : document.scrollingElement(); |
+ |
+ ScrollDirection orientation; |
+ if (!StringToScrollDirection(options.orientation(), &orientation)) { |
+ exception_state.ThrowDOMException(kNotSupportedError, |
+ "Invalid orientation"); |
+ return nullptr; |
+ } |
+ |
+ // TODO(smcgruer): Support 'auto' value. |
+ if (options.timeRange().isScrollTimelineAutoKeyword()) { |
+ exception_state.ThrowDOMException( |
+ kNotSupportedError, "'auto' value for timeRange not yet supported"); |
+ return nullptr; |
+ } |
+ |
+ return new ScrollTimeline(document, scroll_source, orientation, |
+ options.timeRange().getAsDouble()); |
+} |
+ |
+ScrollTimeline::ScrollTimeline(const Document& document, |
+ Element* scroll_source, |
+ ScrollDirection orientation, |
+ double time_range) |
+ : AnimationTimeline(const_cast<Document*>(&document), nullptr), |
+ scroll_source_(scroll_source), |
+ orientation_(orientation), |
+ time_range_(time_range) {} |
+ |
+double ScrollTimeline::currentTime(bool& is_null) { |
+ // 1. If scrollSource does not currently have a CSS layout box, or if its |
+ // layout box is not a scroll container, return an unresolved time value. |
+ LayoutBox* layout_box = scroll_source_->GetLayoutBox(); |
+ if (!layout_box || !layout_box->HasOverflowClip()) { |
+ is_null = true; |
+ return std::numeric_limits<double>::quiet_NaN(); |
+ } |
+ |
+ // 2. Otherwise, let current scroll offset be the current scroll offset of |
+ // scrollSource in the direction specified by orientation. |
+ |
+ // 'auto' ScrollDirection is specified as: If only one direction is |
+ // scrollable, selects that direction. Otherwise selects the direction along |
+ // the block axis. |
+ ScrollDirection local_orientation = orientation_; |
+ bool is_horizontal = layout_box->IsHorizontalWritingMode(); |
+ if (local_orientation == Auto) { |
+ if (layout_box->HasScrollableOverflowX() && |
+ !layout_box->HasScrollableOverflowY()) { |
+ local_orientation = is_horizontal ? Inline : Block; |
+ } else if (!layout_box->HasScrollableOverflowX() && |
+ layout_box->HasScrollableOverflowY()) { |
+ local_orientation = is_horizontal ? Block : Inline; |
+ } else { |
+ // Either neither or both axes are scrollable, so select the block |
+ // direction. |
+ local_orientation = Block; |
+ } |
+ } |
+ |
+ // Depending on the writing-mode and direction, the scroll origin shifts and |
+ // the scroll offset may be negative. The easiest way to deal with this is to |
+ // use only the magnitude of the scroll offset, and compare it to (max-offset |
+ // - min_offset). |
flackr
2017/05/18 15:11:50
There is always the risk that the max or min may n
smcgruer
2017/05/18 15:42:57
Added a DCHECK, since this is a pre-requisite of t
|
+ PaintLayerScrollableArea* scrollable_area = layout_box->GetScrollableArea(); |
+ ScrollOffset scroll_offset = scrollable_area->GetScrollOffset(); |
+ ScrollOffset scroll_dimensions = scrollable_area->MaximumScrollOffset() - |
+ scrollable_area->MinimumScrollOffset(); |
+ |
+ double current_offset; |
+ double max_offset; |
+ DCHECK(local_orientation == Block || local_orientation == Inline); |
+ if (local_orientation == Block) { |
+ current_offset = |
+ is_horizontal ? scroll_offset.Height() : scroll_offset.Width(); |
+ max_offset = |
+ is_horizontal ? scroll_dimensions.Height() : scroll_dimensions.Width(); |
+ } else { |
+ current_offset = |
+ is_horizontal ? scroll_offset.Width() : scroll_offset.Height(); |
+ max_offset = |
+ is_horizontal ? scroll_dimensions.Width() : scroll_dimensions.Height(); |
+ } |
+ |
+ // 3. If current scroll offset is less than startScrollOffset, return an |
+ // unresolved time value if fill is none or forwards, or 0 otherwise. |
+ // TODO(smcgruer): Implement |startScrollOffset| and |fill|. |
+ |
+ // 4. If current scroll offset is greater than or equal to endScrollOffset, |
+ // return an unresolved time value if fill is none or backwards, or the |
+ // effective time range otherwise. |
+ // TODO(smcgruer): Implement |endScrollOffset| and |fill|. |
+ |
+ // 5. Return the result of evaluating the following expression: |
+ // ((current scroll offset - startScrollOffset) / |
+ // (endScrollOffset - startScrollOffset)) * effective time range |
+ |
+ is_null = false; |
+ return (std::abs(current_offset) / max_offset) * time_range_; |
+} |
+ |
+double ScrollTimeline::currentTime() { |
+ bool ignored; |
+ return currentTime(ignored); |
+} |
+ |
+double ScrollTimeline::CurrentTimeInternal(bool& is_null) { |
+ return currentTime(is_null); |
+} |
+ |
+double ScrollTimeline::CurrentTimeInternal() { |
+ bool ignored; |
+ return currentTime(ignored); |
+} |
+ |
+Element* ScrollTimeline::scrollSource() { |
+ return scroll_source_.Get(); |
+} |
+ |
+String ScrollTimeline::orientation() { |
+ switch (orientation_) { |
+ case Auto: |
+ return "auto"; |
+ case Block: |
+ return "block"; |
+ case Inline: |
+ return "inline"; |
+ } |
+} |
+ |
+void ScrollTimeline::timeRange(DoubleOrScrollTimelineAutoKeyword& result) { |
+ result.setDouble(time_range_); |
+} |
+ |
+DEFINE_TRACE(ScrollTimeline) { |
+ visitor->Trace(scroll_source_); |
+ AnimationTimeline::Trace(visitor); |
+} |
+ |
+} // namespace blink |