Commit 44237366 authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Fix compositor ScrollTimeline handling of writing-modes

Previously we would get writing-modes/directionality completely
wrong for composited ScrollTimelines. This CL teaches cc::ScrollTimeline
about 'reverse' axes, without exposing the concepts of writing-mode or
directionality to it.

Bug: 906115
Change-Id: Id843668956b0766469148c1ae6ad33fca582ba63
Reviewed-on: https://chromium-review.googlesource.com/c/1310567
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Reviewed-by: default avatarMajid Valipour <majidvp@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608987}
parent 3b4fb711
...@@ -328,8 +328,9 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) { ...@@ -328,8 +328,9 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) {
// Create scroll timeline that links scroll animation and worklet animation // Create scroll timeline that links scroll animation and worklet animation
// together. Use timerange so that we have 1:1 time & scroll mapping. // together. Use timerange so that we have 1:1 time & scroll mapping.
auto scroll_timeline = std::make_unique<ScrollTimeline>( auto scroll_timeline =
element_id, ScrollTimeline::Vertical, base::nullopt, base::nullopt, 100); std::make_unique<ScrollTimeline>(element_id, ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt, 100);
// Create a worklet animation that is bound to the scroll timeline. // Create a worklet animation that is bound to the scroll timeline.
scoped_refptr<WorkletAnimation> worklet_animation( scoped_refptr<WorkletAnimation> worklet_animation(
......
...@@ -11,14 +11,26 @@ ...@@ -11,14 +11,26 @@
namespace cc { namespace cc {
namespace {
bool IsVertical(ScrollTimeline::ScrollDirection direction) {
return direction == ScrollTimeline::ScrollUp ||
direction == ScrollTimeline::ScrollDown;
}
bool IsReverse(ScrollTimeline::ScrollDirection direction) {
return direction == ScrollTimeline::ScrollUp ||
direction == ScrollTimeline::ScrollLeft;
}
} // namespace
ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id, ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id,
ScrollDirection orientation, ScrollDirection direction,
base::Optional<double> start_scroll_offset, base::Optional<double> start_scroll_offset,
base::Optional<double> end_scroll_offset, base::Optional<double> end_scroll_offset,
double time_range) double time_range)
: active_id_(), : active_id_(),
pending_id_(scroller_id), pending_id_(scroller_id),
orientation_(orientation), direction_(direction),
start_scroll_offset_(start_scroll_offset), start_scroll_offset_(start_scroll_offset),
end_scroll_offset_(end_scroll_offset), end_scroll_offset_(end_scroll_offset),
time_range_(time_range) {} time_range_(time_range) {}
...@@ -26,7 +38,7 @@ ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id, ...@@ -26,7 +38,7 @@ ScrollTimeline::ScrollTimeline(base::Optional<ElementId> scroller_id,
ScrollTimeline::~ScrollTimeline() {} ScrollTimeline::~ScrollTimeline() {}
std::unique_ptr<ScrollTimeline> ScrollTimeline::CreateImplInstance() const { std::unique_ptr<ScrollTimeline> ScrollTimeline::CreateImplInstance() const {
return std::make_unique<ScrollTimeline>(pending_id_, orientation_, return std::make_unique<ScrollTimeline>(pending_id_, direction_,
start_scroll_offset_, start_scroll_offset_,
end_scroll_offset_, time_range_); end_scroll_offset_, time_range_);
} }
...@@ -58,11 +70,15 @@ double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree, ...@@ -58,11 +70,15 @@ double ScrollTimeline::CurrentTime(const ScrollTree& scroll_tree,
gfx::ScrollOffset scroll_dimensions = gfx::ScrollOffset scroll_dimensions =
scroll_tree.MaxScrollOffset(scroll_node->id); scroll_tree.MaxScrollOffset(scroll_node->id);
double current_offset = (orientation_ == Vertical) ? offset.y() : offset.x(); double max_offset =
double max_offset = (orientation_ == Vertical) ? scroll_dimensions.y() IsVertical(direction_) ? scroll_dimensions.y() : scroll_dimensions.x();
: scroll_dimensions.x(); double current_physical_offset =
DCHECK_GE(current_offset, 0); IsVertical(direction_) ? offset.y() : offset.x();
double current_offset = IsReverse(direction_)
? max_offset - current_physical_offset
: current_physical_offset;
DCHECK_GE(max_offset, 0); DCHECK_GE(max_offset, 0);
DCHECK_GE(current_offset, 0);
double resolved_start_scroll_offset = start_scroll_offset_.value_or(0); double resolved_start_scroll_offset = start_scroll_offset_.value_or(0);
double resolved_end_scroll_offset = end_scroll_offset_.value_or(max_offset); double resolved_end_scroll_offset = end_scroll_offset_.value_or(max_offset);
......
...@@ -17,18 +17,18 @@ class ScrollTree; ...@@ -17,18 +17,18 @@ class ScrollTree;
// progress of scrolling in some scroll container. // progress of scrolling in some scroll container.
// //
// This is the compositor-side representation of the web concept expressed in // This is the compositor-side representation of the web concept expressed in
// https://wicg.github.io/scroll-animations/#scrolltimeline-interface. There are // https://wicg.github.io/scroll-animations/#scrolltimeline-interface.
// differences between this class and the web definition of a ScrollTimeline.
// For example the compositor does not know (or care) about 'writing modes', so
// this class only tracks whether the ScrollTimeline orientation is horizontal
// or vertical. Blink is expected to resolve any such 'web' requirements and
// construct/update the compositor ScrollTimeline accordingly.
class CC_ANIMATION_EXPORT ScrollTimeline { class CC_ANIMATION_EXPORT ScrollTimeline {
public: public:
enum ScrollDirection { Horizontal, Vertical }; enum ScrollDirection {
ScrollUp,
ScrollDown,
ScrollLeft,
ScrollRight,
};
ScrollTimeline(base::Optional<ElementId> scroller_id, ScrollTimeline(base::Optional<ElementId> scroller_id,
ScrollDirection orientation, ScrollDirection direction,
base::Optional<double> start_scroll_offset, base::Optional<double> start_scroll_offset,
base::Optional<double> end_scroll_offset, base::Optional<double> end_scroll_offset,
double time_range); double time_range);
...@@ -60,9 +60,9 @@ class CC_ANIMATION_EXPORT ScrollTimeline { ...@@ -60,9 +60,9 @@ class CC_ANIMATION_EXPORT ScrollTimeline {
base::Optional<ElementId> active_id_; base::Optional<ElementId> active_id_;
base::Optional<ElementId> pending_id_; base::Optional<ElementId> pending_id_;
// The orientation of the ScrollTimeline indicates which axis of the scroller // The direction of the ScrollTimeline indicates which axis of the scroller
// it should base its current time on - either the horizontal or vertical. // it should base its current time on, and where the origin point is.
ScrollDirection orientation_; ScrollDirection direction_;
base::Optional<double> start_scroll_offset_; base::Optional<double> start_scroll_offset_;
base::Optional<double> end_scroll_offset_; base::Optional<double> end_scroll_offset_;
......
...@@ -98,9 +98,9 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) { ...@@ -98,9 +98,9 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) {
// just compute one edge and use it for vertical/horizontal. // just compute one edge and use it for vertical/horizontal.
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
ScrollTimeline vertical_timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline vertical_timeline(scroller_id(), ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt, time_range); base::nullopt, base::nullopt, time_range);
ScrollTimeline horizontal_timeline(scroller_id(), ScrollTimeline::Horizontal, ScrollTimeline horizontal_timeline(scroller_id(), ScrollTimeline::ScrollRight,
base::nullopt, base::nullopt, time_range); base::nullopt, base::nullopt, time_range);
// Unscrolled, both timelines should read a current time of 0. // Unscrolled, both timelines should read a current time of 0.
...@@ -120,7 +120,7 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) { ...@@ -120,7 +120,7 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) {
TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) { TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) {
// Here we set a time range to 100, which gives the current time the form of // Here we set a time range to 100, which gives the current time the form of
// 'percentage scrolled'. // 'percentage scrolled'.
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt, 100); base::nullopt, base::nullopt, 100);
double halfwayY = (content_size().height() - container_size().height()) / 2.; double halfwayY = (content_size().height() - container_size().height()) / 2.;
...@@ -153,7 +153,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) { ...@@ -153,7 +153,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) {
double halfwayY = (content_size().height() - container_size().height()) / 2.; double halfwayY = (content_size().height() - container_size().height()) / 2.;
SetScrollOffset(&pending_tree, scroller_id, gfx::ScrollOffset(0, halfwayY)); SetScrollOffset(&pending_tree, scroller_id, gfx::ScrollOffset(0, halfwayY));
ScrollTimeline main_timeline(scroller_id, ScrollTimeline::Vertical, ScrollTimeline main_timeline(scroller_id, ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt, 100); base::nullopt, base::nullopt, 100);
// Now create an impl version of the ScrollTimeline. Initilly this should only // Now create an impl version of the ScrollTimeline. Initilly this should only
...@@ -180,7 +180,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) { ...@@ -180,7 +180,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) {
TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) { TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt, time_range); base::nullopt, base::nullopt, time_range);
SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 50)); SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 50));
...@@ -197,7 +197,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) { ...@@ -197,7 +197,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) {
TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) { TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
const double start_scroll_offset = 20; const double start_scroll_offset = 20;
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown,
start_scroll_offset, base::nullopt, time_range); start_scroll_offset, base::nullopt, time_range);
// Unscrolled, the timeline should read a current time of unresolved, since // Unscrolled, the timeline should read a current time of unresolved, since
...@@ -222,7 +222,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) { ...@@ -222,7 +222,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) {
TEST_F(ScrollTimelineTest, CurrentTimeHandlesEndScrollOffset) { TEST_F(ScrollTimelineTest, CurrentTimeHandlesEndScrollOffset) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
const double end_scroll_offset = time_range - 20; const double end_scroll_offset = time_range - 20;
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown,
base::nullopt, end_scroll_offset, time_range); base::nullopt, end_scroll_offset, time_range);
SetScrollOffset(&property_trees(), scroller_id(), SetScrollOffset(&property_trees(), scroller_id(),
...@@ -249,7 +249,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) { ...@@ -249,7 +249,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
double start_scroll_offset = 20; double start_scroll_offset = 20;
double end_scroll_offset = time_range - 50; double end_scroll_offset = time_range - 50;
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown,
start_scroll_offset, end_scroll_offset, time_range); start_scroll_offset, end_scroll_offset, time_range);
SetScrollOffset(&property_trees(), scroller_id(), SetScrollOffset(&property_trees(), scroller_id(),
gfx::ScrollOffset(0, time_range - 150)); gfx::ScrollOffset(0, time_range - 150));
...@@ -260,7 +260,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) { ...@@ -260,7 +260,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) {
TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) { TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, 20, 20, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, 20, 20,
time_range); time_range);
SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150)); SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150));
EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false)));
...@@ -269,7 +269,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) { ...@@ -269,7 +269,7 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) {
TEST_F(ScrollTimelineTest, TEST_F(ScrollTimelineTest,
CurrentTimeHandlesStartOffsetLargerThanEndScrollOffset) { CurrentTimeHandlesStartOffsetLargerThanEndScrollOffset) {
double time_range = content_size().height() - container_size().height(); double time_range = content_size().height() - container_size().height();
ScrollTimeline timeline(scroller_id(), ScrollTimeline::Vertical, 50, 10, ScrollTimeline timeline(scroller_id(), ScrollTimeline::ScrollDown, 50, 10,
time_range); time_range);
SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150)); SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 150));
EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false))); EXPECT_TRUE(std::isnan(timeline.CurrentTime(scroll_tree(), false)));
......
...@@ -50,7 +50,7 @@ class MockScrollTimeline : public ScrollTimeline { ...@@ -50,7 +50,7 @@ class MockScrollTimeline : public ScrollTimeline {
public: public:
MockScrollTimeline() MockScrollTimeline()
: ScrollTimeline(ElementId(), : ScrollTimeline(ElementId(),
ScrollTimeline::Vertical, ScrollTimeline::ScrollDown,
base::nullopt, base::nullopt,
base::nullopt, base::nullopt,
0) {} 0) {}
......
...@@ -4,14 +4,22 @@ function runInAnimationWorklet(code) { ...@@ -4,14 +4,22 @@ function runInAnimationWorklet(code) {
); );
} }
function waitForAnimationFrames(count, callback) {
function rafCallback() {
if (count <= 0) {
callback();
} else {
count -= 1;
window.requestAnimationFrame(rafCallback);
}
}
rafCallback();
};
// Wait for two main thread frames to guarantee that compositor has produced // Wait for two main thread frames to guarantee that compositor has produced
// at least one frame. // at least one frame.
function waitTwoAnimationFrames(callback){ function waitTwoAnimationFrames(callback) {
window.requestAnimationFrame( _=> { waitForAnimationFrames(2, callback);
window.requestAnimationFrame( _ => {
callback();
})
});
}; };
// Load test cases in worklet context in sequence and wait until they are resolved. // Load test cases in worklet context in sequence and wait until they are resolved.
......
<!DOCTYPE html>
<title>Tests that ScrollTimeline works properly with writing mode and directionality</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script id="worklet_code" type="text/worklet">
registerAnimator("test_animator", class {
animate(currentTime, effect) {
effect.localTime = currentTime;
}
});
</script>
<script src="resources/animation-worklet-tests.js"></script>
<script>
// Creates a DOM structure like:
// - container
// - box {100x100}
// - scroller {100x100, writing-mode, direction}
// - contents
function createTestDOM(x_scroll_axis, writing_mode, direction) {
const elements = {};
elements.container = document.createElement('div');
elements.box = document.createElement('div');
elements.box.style.height = '100px';
elements.box.style.width = '100px';
elements.scroller = document.createElement('div');
elements.scroller.style.height = '100px';
elements.scroller.style.width = '100px';
if (x_scroll_axis)
elements.scroller.style.overflowX = 'scroll';
else
elements.scroller.style.overflowY = 'scroll';
elements.scroller.style.direction = direction;
elements.scroller.style.writingMode = writing_mode;
// Callers don't need access to this.
const contents = document.createElement('div');
contents.style.height = x_scroll_axis ? '100%' : '1000px';
contents.style.width = x_scroll_axis ? '1000px' : '100%';
elements.scroller.appendChild(contents);
elements.container.appendChild(elements.box);
elements.container.appendChild(elements.scroller);
document.body.appendChild(elements.container);
return elements;
}
function createAndPlayTestAnimation(elements, timeline_orientation) {
const effect = new KeyframeEffect(
elements.box,
[{transform: 'translateY(0)'}, {transform: 'translateY(200px)'}], {
duration: 1000,
});
const timeline = new ScrollTimeline({
scrollSource: elements.scroller,
timeRange: 1000,
orientation: timeline_orientation
});
const animation = new WorkletAnimation('test_animator', effect, timeline);
animation.play();
}
setup(setupAndRegisterTests, {explicit_done: true});
function setupAndRegisterTests() {
const worklet_code = document.getElementById('worklet_code').textContent;
runInAnimationWorklet(worklet_code).then(() => {
// Note that block horizontal-tb is tested implicitly in the basic
// ScrollTimeline tests (as it is the default).
async_test(
block_vertical_lr,
'A block ScrollTimeline should produce the correct current time for vertical-lr');
async_test(
block_vertical_rl,
'A block ScrollTimeline should produce the correct current time for vertical-rl');
// Again, inline for horizontal-tb and direction: ltr is the default
// inline mode and so is tested elsewhere.
async_test(
inline_horizontal_tb_rtl,
'An inline ScrollTimeline should produce the correct current time for horizontal-tb and direction: rtl');
async_test(
inline_vertical_writing_mode_ltr,
'An inline ScrollTimeline should produce the correct current time for vertical writing mode');
async_test(
inline_vertical_writing_mode_rtl,
'An inline ScrollTimeline should produce the correct current time for vertical writing mode and direction: rtl');
done();
});
}
function block_vertical_lr(t) {
const elements = createTestDOM(true, 'vertical-lr', 'ltr');
createAndPlayTestAnimation(elements, 'block');
// Move the scroller to the 25% point.
const maxScroll =
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
}
function block_vertical_rl(t) {
const elements = createTestDOM(true, 'vertical-rl', 'ltr');
createAndPlayTestAnimation(elements, 'block');
// Move the scroller to the 75% point. Since it is vertical-rl, this is
// equivalent to the 25% point for the ScrollTimeline.
const maxScroll =
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
}
function inline_horizontal_tb_rtl(t) {
const elements = createTestDOM(true, 'horizontal-tb', 'rtl');
createAndPlayTestAnimation(elements, 'inline');
// Move the scroller to the 75% point. Since it is direction: rtl, this is
// equivalent to the 25% point for the ScrollTimeline.
const maxScroll =
elements.scroller.scrollWidth - elements.scroller.clientWidth;
elements.scroller.scrollLeft = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
}
function inline_vertical_writing_mode_ltr(t) {
const elements = createTestDOM(false, 'vertical-lr', 'ltr');
createAndPlayTestAnimation(elements, 'inline');
// Move the scroller to the 25% point.
const maxScroll =
elements.scroller.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.25 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
}
function inline_vertical_writing_mode_rtl(t) {
const elements = createTestDOM(false, 'vertical-lr', 'rtl');
createAndPlayTestAnimation(elements, 'inline');
// Move the scroller to the 75% point. Since this is a vertical writing mode
// and direction: rtl, this is 25% of the ScrollTimeline currentTime.
const maxScroll =
elements.scroller.scrollHeight - elements.scroller.clientHeight;
elements.scroller.scrollTop = 0.75 * maxScroll;
waitForAnimationFrames(3, t.step_func_done(() => {
assert_equals(
getComputedStyle(elements.box).transform, 'matrix(1, 0, 0, 1, 0, 50)');
}));
}
</script>
...@@ -136,26 +136,56 @@ base::Optional<CompositorElementId> GetCompositorScrollElementId( ...@@ -136,26 +136,56 @@ base::Optional<CompositorElementId> GetCompositorScrollElementId(
// web concepts of 'block' and 'inline' direction into absolute vertical or // web concepts of 'block' and 'inline' direction into absolute vertical or
// horizontal directions. // horizontal directions.
// //
// This implements a subset of the conversions documented in
// https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
//
// TODO(smcgruer): If the writing mode of a scroller changes, we have to update // TODO(smcgruer): If the writing mode of a scroller changes, we have to update
// any related cc::ScrollTimeline somehow. // any related cc::ScrollTimeline somehow.
CompositorScrollTimeline::ScrollDirection ConvertOrientation( CompositorScrollTimeline::ScrollDirection ConvertOrientation(
ScrollTimeline::ScrollDirection orientation, ScrollTimeline::ScrollDirection orientation,
bool is_horizontal_writing_mode) { const ComputedStyle* style) {
switch (orientation) { // Easy cases; physical is always physical.
case ScrollTimeline::Block: if (orientation == ScrollTimeline::Horizontal)
return is_horizontal_writing_mode ? CompositorScrollTimeline::Vertical return CompositorScrollTimeline::ScrollRight;
: CompositorScrollTimeline::Horizontal; if (orientation == ScrollTimeline::Vertical)
case ScrollTimeline::Inline: return CompositorScrollTimeline::ScrollDown;
return is_horizontal_writing_mode ? CompositorScrollTimeline::Horizontal
: CompositorScrollTimeline::Vertical; // Harder cases; first work out which axis is which, and then for each check
case ScrollTimeline::Horizontal: // which edge we start at.
return CompositorScrollTimeline::Horizontal;
case ScrollTimeline::Vertical: // writing-mode: horizontal-tb
return CompositorScrollTimeline::Vertical; bool is_horizontal_writing_mode =
default: style ? style->IsHorizontalWritingMode() : true;
NOTREACHED(); // writing-mode: vertical-lr
return CompositorScrollTimeline::Vertical; bool is_flipped_lines_writing_mode =
style ? style->IsFlippedLinesWritingMode() : false;
// direction: ltr;
bool is_ltr_direction = style ? style->IsLeftToRightDirection() : true;
if (orientation == ScrollTimeline::Block) {
if (is_horizontal_writing_mode) {
// For horizontal writing mode, block is vertical. The starting edge is
// always the top.
return CompositorScrollTimeline::ScrollDown;
}
// For vertical writing mode, the block axis is horizontal. The starting
// edge depends on if we are lr or rl.
return is_flipped_lines_writing_mode ? CompositorScrollTimeline::ScrollRight
: CompositorScrollTimeline::ScrollLeft;
}
DCHECK_EQ(orientation, ScrollTimeline::Inline);
if (is_horizontal_writing_mode) {
// For horizontal writing mode, inline is horizontal. The starting edge
// depends on the directionality.
return is_ltr_direction ? CompositorScrollTimeline::ScrollRight
: CompositorScrollTimeline::ScrollLeft;
} }
// For vertical writing mode, inline is vertical. The starting edge still
// depends on the directionality; whether it is vertical-lr or vertical-rl
// does not matter.
return is_ltr_direction ? CompositorScrollTimeline::ScrollDown
: CompositorScrollTimeline::ScrollUp;
} }
// Converts a blink::ScrollTimeline into a cc::ScrollTimeline. // Converts a blink::ScrollTimeline into a cc::ScrollTimeline.
...@@ -181,9 +211,8 @@ std::unique_ptr<CompositorScrollTimeline> ToCompositorScrollTimeline( ...@@ -181,9 +211,8 @@ std::unique_ptr<CompositorScrollTimeline> ToCompositorScrollTimeline(
// correct orientation and start/end offset information. // correct orientation and start/end offset information.
LayoutBox* box = scroll_source->GetLayoutBox(); LayoutBox* box = scroll_source->GetLayoutBox();
CompositorScrollTimeline::ScrollDirection orientation = CompositorScrollTimeline::ScrollDirection orientation = ConvertOrientation(
ConvertOrientation(scroll_timeline->GetOrientation(), scroll_timeline->GetOrientation(), box ? box->Style() : nullptr);
box ? box->IsHorizontalWritingMode() : true);
base::Optional<double> start_scroll_offset; base::Optional<double> start_scroll_offset;
base::Optional<double> end_scroll_offset; base::Optional<double> end_scroll_offset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment