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..3b32773c449dd793fef97435f46d4a9454cbb442 |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/core/animation/ScrollTimeline.cpp |
| @@ -0,0 +1,161 @@ |
| +// 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) { |
| + // TODO(smcgruer): Support 'auto' value. |
| + 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) {} |
|
alancutter (OOO until 2018)
2017/06/08 05:00:31
We should assert that the RuntimeEnabledFeature fl
smcgruer
2017/06/08 14:43:47
Done.
|
| + |
| +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 = false; |
| + 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. |
| + |
| + // 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(); |
| + // Using the absolute value of the scroll offset only makes sense if either |
| + // the max or min scroll offset for a given axis is 0. This should be |
| + // guaranteed by the scroll origin code, but these DCHECKs ensure that. |
| + DCHECK(scrollable_area->MaximumScrollOffset().Height() == 0 || |
| + scrollable_area->MinimumScrollOffset().Height() == 0); |
| + DCHECK(scrollable_area->MaximumScrollOffset().Width() == 0 || |
| + scrollable_area->MinimumScrollOffset().Width() == 0); |
| + ScrollOffset scroll_offset = scrollable_area->GetScrollOffset(); |
| + ScrollOffset scroll_dimensions = scrollable_area->MaximumScrollOffset() - |
| + scrollable_area->MinimumScrollOffset(); |
| + |
| + double current_offset; |
| + double max_offset; |
| + 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 { |
| + 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 Block: |
| + return "block"; |
| + case Inline: |
| + return "inline"; |
| + default: |
| + NOTREACHED(); |
| + return ""; |
| + } |
| +} |
| + |
| +void ScrollTimeline::timeRange(DoubleOrScrollTimelineAutoKeyword& result) { |
| + result.setDouble(time_range_); |
| +} |
| + |
| +DEFINE_TRACE(ScrollTimeline) { |
| + visitor->Trace(scroll_source_); |
| + AnimationTimeline::Trace(visitor); |
| +} |
| + |
| +} // namespace blink |