<!DOCTYPE html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/gesture-util.js"></script>
<script src="../../resources/percent-based-util.js"></script>
<script src="../../resources/testdriver.js"></script>
<script src="../../resources/testdriver-actions.js"></script>
<script src="../../resources/testdriver-vendor.js"></script>
<style>
body {
margin: 0;
}
.outer {
height: 250px;
width: 500px;
}
.content {
height: calc(100vh + 100px);
width: calc(100vw + 100px);
}
#container {
overflow: scroll;
}
#non_scrollable {
background-color: #eee;
overflow: hidden;
}
</style>
<div id='non_scrollable' class='outer'>
<div class='content'></div>
</div>
<div id='container' class='outer'>
<div class='content'></div>
</div>
<div class="content"></div>
<script>
const container = document.getElementById('container');
const non_scrollable = document.getElementById('non_scrollable');
const scrollAmount = 120;
const scrollLeft = { dx: -scrollAmount, dy: 0 };
const scrollUp = { dx: 0, dy: -scrollAmount };
const scrollRight = { dx: scrollAmount, dy: 0 };
const scrollDown = { dx: 0, dy: scrollAmount };
const scrollUpAndLeft = { dx: -scrollAmount, dy: -scrollAmount };
const startPositionCenter = { x: 0.5, y: 0.5 };
const startPositionBottom = { x: 0.5, y: 0.9 };
async function setUpForWindow() {
await waitForCompositorCommit();
await waitForScrollReset(document.scrollingElement, 100, 100);
await waitForScrollReset(container, 0, 0);
assert_equals(window.scrollY, 100);
assert_equals(window.scrollX, 100);
assert_equals(container.scrollTop, 0);
assert_equals(container.scrollLeft, 0);
}
async function setUpForContainer() {
await waitForCompositorCommit();
await waitForScrollReset(document.scrollingElement, 0, 0);
await waitForScrollReset(container, 100, 100);
assert_equals(window.scrollY, 0);
assert_equals(window.scrollX, 0);
assert_equals(container.scrollTop, 100);
assert_equals(container.scrollLeft, 100);
}
// Performs a wheel scroll or touch drag gesture that may result in scrolling.
// If scrollEventTarget is not null, it indicates the target for the scrollend
// event.
function performGestureScroll(element, startPosition, deltaX, deltaY, gesture,
scrollEventTarget) {
// Pick a starting point within the element with room to accommodate the
// scroll gesture.
const position = elementPosition(element, startPosition.x, startPosition.y);
assert_point_within_viewport(position.x, position.y);
const promises = [];
if (scrollEventTarget) {
promises.push(waitForScrollendEvent(scrollEventTarget));
}
promises.push(gesture(position.x, position.y, deltaX, deltaY));
return Promise.all(promises);
};
function performWheelScroll(element, startPosition, scrollAmount,
scrollEventTarget = null) {
const scroll = (x, y, dx, dy) => {
return wheelScroll(x, y, dx, dy, scrollEventTarget);
};
return performGestureScroll(element, startPosition, scrollAmount.dx,
scrollAmount.dy, scroll, scrollEventTarget);
}
function performTouchDrag(element, startPosition, scrollAmount,
scrollEventTarget = null) {
// Touch scrolling is in the opposite direction to the drag.
return performGestureScroll(element, startPosition, -scrollAmount.dx,
-scrollAmount.dy, touchDrag, scrollEventTarget);
}
async function test_boundary_prevents_y(scrollGesture) {
container.style.overscrollBehaviorX = 'auto';
container.style.overscrollBehaviorY = 'none';
await setUpForWindow();
// Scroll-chaining blocked by overscroll-behavior-y.
await scrollGesture(container, startPositionCenter, scrollUp);
assert_equals(window.scrollY, 100);
assert_equals(container.scrollTop, 0);
await raf();
// Scroll-chaining permitted by overscroll-behavior-x.
await scrollGesture(container, startPositionCenter, scrollLeft, document);
assert_equals(window.scrollX, 0);
assert_equals(container.scrollLeft, 0);
}
async function test_boundary_prevents_x(scrollGesture) {
container.style.overscrollBehaviorX = 'none';
container.style.overscrollBehaviorY = 'auto';
await setUpForWindow();
// Scroll-chaining blocked by overscroll-behavior-x.
await scrollGesture(container, startPositionCenter, scrollLeft);
assert_equals(window.scrollX, 100);
assert_equals(container.scrollLeft, 0);
await raf();
// Scroll-chaining permitted by overscroll-behavior-y.
await scrollGesture(container, startPositionCenter, scrollUp, document);
assert_equals(window.scrollY, 0);
assert_equals(container.scrollTop, 0);
}
async function test_boundary_allows_inner(scrollGesture) {
container.style.overscrollBehaviorX = 'none';
container.style.overscrollBehaviorY = 'none';
await setUpForContainer();
await scrollGesture(container, startPositionCenter, scrollUpAndLeft,
container);
assert_equals(container.scrollTop, 0);
assert_equals(container.scrollLeft, 0);
}
async function test_boundary_on_nonscrollable_allows_propagation(scrollGesture)
{
non_scrollable.style.overscrollBehaviorX = 'none';
non_scrollable.style.overscrollBehaviorY = 'none';
await waitForCompositorCommit;
await waitForScrollReset(document.scrollingElement);
await scrollGesture(non_scrollable, startPositionBottom, scrollRight,
document);
assert_greater_than(window.scrollX, 100);
await raf();
await scrollGesture(non_scrollable, startPositionBottom, scrollDown,
document);
assert_greater_than(window.scrollY, 100);
}
promise_test(t => {
return test_boundary_prevents_y(performWheelScroll);
}, 'overscroll-behavior-y: none should only prevent scroll propagation on y ' +
'axis with: wheel.');
promise_test(t => {
return test_boundary_prevents_x(performWheelScroll);
}, 'overscroll-behavior-x: none should only prevent scroll propagation on x ' +
'axis with: wheel.');
promise_test(t => {
return test_boundary_allows_inner(performWheelScroll);
}, 'overscroll-behavior should not affect scrolling inside the applied ' +
'container with: wheel.');
promise_test(t => {
return test_boundary_on_nonscrollable_allows_propagation(performWheelScroll);
}, 'overscroll-behavior on non-scrollable area should not affect scroll ' +
'propagation with: wheel.');
const IS_MAC = navigator.platform.indexOf('Mac') == 0;
if (!IS_MAC) {
promise_test(t => {
return test_boundary_prevents_y(performTouchDrag);
}, 'overscroll-behavior-y: none should only prevent scroll propagation on ' +
'y axis with: touch.');
promise_test(t => {
return test_boundary_prevents_x(performTouchDrag);
}, 'overscroll-behavior-x: none should only prevent scroll propagation on ' +
'x axis with: touch.');
promise_test(t => {
return test_boundary_on_nonscrollable_allows_propagation(
performTouchDrag);
}, 'overscroll-behavior on non-scrollable area should not affect scroll ' +
'propagation with: touch.');
}
</script>