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..de235c95578556daae90a39909008f0663571053 |
| --- /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) { |
| + 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) { |
| + // TODO(smcgruer): The spec allows for a null scrollSource. |
|
majidvp
2017/05/15 14:38:52
Hmmm, I presume that if the scrollSource is not sp
smcgruer
2017/05/15 15:22:54
Nope, spec defines it as follows (https://wicg.git
flackr
2017/05/15 17:29:06
Note, probably should be the document.scrollingEle
smcgruer
2017/05/16 19:24:47
Filed https://github.com/WICG/scroll-animations/is
|
| + if (!options.scrollSource()) { |
| + exception_state.ThrowDOMException(kNotSupportedError, |
| + "A scrollSource must be specified"); |
| + return nullptr; |
| + } |
| + |
| + 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 new ScrollTimeline(document, options.scrollSource(), 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->GetScrollableArea()) { |
|
majidvp
2017/05/15 14:38:52
I don't think layout_box->GetScrollableArea() maps
smcgruer
2017/05/15 15:22:54
Ah, so looks like by the spec we just want to chec
flackr
2017/05/15 17:29:06
LayoutObject::HasOverflowClip
smcgruer
2017/05/16 19:24:47
Done.
|
| + LOG(INFO) << "!layout_box || !layout_box->GetScrollableArea()"; |
| + 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. |
| + ScrollDirection local_orientation = orientation_; |
| + if (local_orientation == Auto) { |
| + // If only one direction is scrollable, selects that direction. Otherwise |
| + // selects the direction along the block axis. |
| + DCHECK(layout_box->HasScrollableOverflowX() || |
| + layout_box->HasScrollableOverflowY()); |
|
flackr
2017/05/15 17:29:06
I don't think this check is correct. We could have
smcgruer
2017/05/17 15:52:03
Done.
|
| + local_orientation = layout_box->HasScrollableOverflowY() ? Block : Inline; |
|
flackr
2017/05/15 17:29:06
Isn't this assuming LTR? I think you'd have to che
smcgruer
2017/05/17 15:52:02
Done.
|
| + } |
| + double current_scroll_offset = 0.0; |
| + double max_scroll_offset = 1.0; |
| + switch (local_orientation) { |
| + case Block: |
| + current_scroll_offset = scroll_source_->scrollTop(); |
| + max_scroll_offset = |
| + scroll_source_->scrollHeight() - scroll_source_->clientHeight(); |
|
majidvp
2017/05/15 14:38:52
Shouldn't we use the logical coordinates here as o
smcgruer
2017/05/15 15:22:54
Possibly. I just wrote this based on a comment in
smcgruer
2017/05/17 15:52:02
Done.
|
| + break; |
| + case Inline: |
| + current_scroll_offset = scroll_source_->scrollLeft(); |
| + max_scroll_offset = |
| + scroll_source_->scrollWidth() - scroll_source_->clientWidth(); |
| + break; |
| + case Auto: |
| + LOG(FATAL) << "local_orientation cannot be Auto"; |
| + break; |
| + } |
| + |
| + // 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_scroll_offset / max_scroll_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 |