Chromium Code Reviews| 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..63472fcbeb811d9c11c6a19b79529f4b8fb7c623 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/core/animation/ScrollTimeline.cpp |
| @@ -0,0 +1,179 @@ |
| +// 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(const Document& document, |
| + ScrollTimelineOptions options, |
| + ExceptionState& exception_state) { |
| + Element* scroll_source = |
| + options.scrollSource() |
| + ? options.scrollSource() |
| + : const_cast<Document&>(document).scrollingElement(); |
|
majidvp
2017/05/17 20:39:45
I believe this should instead use |ScrollingElemen
majidvp
2017/05/17 20:39:45
It is odd that this method is not |const| requirin
smcgruer
2017/05/18 13:58:56
My only concern here is that |scrollingElement()|
smcgruer
2017/05/18 14:17:21
Turns out that the Document& doesnt have to be con
|
| + |
| + 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; |
| + } |
| + } |
|
majidvp
2017/05/17 20:39:45
Should this decision be made every time we query c
smcgruer
2017/05/18 13:58:56
Filed https://github.com/WICG/scroll-animations/is
smcgruer
2017/05/23 14:47:27
https://github.com/WICG/scroll-animations/issues/1
|
| + |
| + // 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). |
| + PaintLayerScrollableArea* scrollable_area = layout_box->GetScrollableArea(); |
| + ScrollOffset abs_scroll_offset = |
| + ScrollOffset(std::abs(scrollable_area->GetScrollOffset().Width()), |
| + std::abs(scrollable_area->GetScrollOffset().Height())); |
| + ScrollOffset max_abs_scroll_offset = scrollable_area->MaximumScrollOffset() - |
|
majidvp
2017/05/17 20:39:45
nit: s/max_abs_scroll_offset/scroll_dimensions/ (
smcgruer
2017/05/18 13:58:56
Done.
|
| + scrollable_area->MinimumScrollOffset(); |
| + |
| + double current_offset; |
| + double max_offset; |
| + DCHECK(local_orientation == Block || local_orientation == Inline); |
| + if (local_orientation == Block) { |
| + current_offset = |
| + is_horizontal ? abs_scroll_offset.Height() : abs_scroll_offset.Width(); |
| + max_offset = is_horizontal ? max_abs_scroll_offset.Height() |
| + : max_abs_scroll_offset.Width(); |
| + } else { |
| + current_offset = |
| + is_horizontal ? abs_scroll_offset.Width() : abs_scroll_offset.Height(); |
| + max_offset = is_horizontal ? max_abs_scroll_offset.Width() |
| + : max_abs_scroll_offset.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 (current_offset / max_offset) * time_range_; |
|
majidvp
2017/05/17 20:39:44
may be cleaner if we just move std::abs operation
smcgruer
2017/05/18 13:58:56
Done.
|
| +} |
| + |
| +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"; |
|
majidvp
2017/05/17 20:39:45
If we decide to resolve "auto" value on constructi
|
| + 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 |