| <!DOCTYPE html> |
| <script src="../../resources/testharness.js"></script> |
| <script src="../../resources/testharnessreport.js"></script> |
| <style> |
| .outer { |
| height: 400px; |
| width: 1000px; |
| } |
| .content { |
| height: 1000px; |
| width: 1200px; |
| } |
| #container { |
| overflow: scroll; |
| } |
| #non_scrollable { |
| overflow: none; |
| } |
| </style> |
| |
| <div id='non_scrollable' class='outer'> |
| <div class='content'></div> |
| </div> |
| <div id='container' class='outer'> |
| <div class='content'></div> |
| </div> |
| |
| <script> |
| const container = document.getElementById('container'); |
| const non_scrollable = document.getElementById('non_scrollable'); |
| |
| function setUpForWindow() { |
| window.scrollTo(100, 100); |
| container.scrollTo(0, 0); |
| assert_equals(window.scrollY, 100); |
| assert_equals(window.scrollX, 100); |
| } |
| |
| function setUpForContainer() { |
| window.scrollTo(0, 0); |
| container.scrollTo(100, 100); |
| assert_equals(container.scrollTop, 100); |
| assert_equals(container.scrollLeft, 100); |
| } |
| |
| function smoothScroll(pixels_to_scroll, start_x, start_y, gesture_source_type, direction, speed_in_pixels_s) { |
| return new Promise((resolve, reject) => { |
| chrome.gpuBenchmarking.smoothScrollBy(pixels_to_scroll, resolve, start_x, start_y, gesture_source_type, direction, speed_in_pixels_s); |
| }); |
| } |
| |
| function waitForAnimationEnd() { |
| const MAX_FRAME = 500; |
| var last_changed_frame = 0; |
| var last_window_x = window.scrollX; |
| var last_window_y = window.scrollY; |
| var last_container_x = container.scrollLeft; |
| var last_container_y = container.scrollTop; |
| return new Promise((resolve, reject) => { |
| function tick(frames) { |
| // We requestAnimationFrame either for 500 frames or until 5 frames with |
| // no change have been observed. |
| if (frames >= MAX_FRAME || frames - last_changed_frame > 5) { |
| resolve(); |
| } else { |
| if (window.scrollX != last_window_x || |
| window.scrollY != last_window_y || |
| container.scrollLeft != last_container_x || |
| container.scrollTop != last_container_y) { |
| last_changed_frame = frames; |
| last_window_x = window.scrollX; |
| last_window_y = window.scrollY; |
| last_container_x = container.scrollLeft; |
| last_container_y = container.scrollTop; |
| } |
| requestAnimationFrame(tick.bind(this, frames + 1)); |
| } |
| } |
| tick(0); |
| }); |
| } |
| |
| function test_boundary_prevents_y(source_type) { |
| container.style.overscrollBehaviorX = 'auto'; |
| container.style.overscrollBehaviorY = 'none'; |
| setUpForWindow(); |
| return smoothScroll(200, 200, 500, source_type, "up", 4000) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_equals(window.scrollY, 100);}) |
| .then( |
| smoothScroll.bind(this, 200, 200, 500, source_type, "left", 4000)) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_equals(window.scrollX, 0); |
| }); |
| } |
| |
| function test_boundary_prevents_x(source_type) { |
| container.style.overscrollBehaviorX = 'none'; |
| container.style.overscrollBehaviorY = 'auto'; |
| setUpForWindow(); |
| return smoothScroll(200, 200, 500, source_type, 'left', 4000) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_equals(window.scrollX, 100);}) |
| .then( |
| smoothScroll.bind(this, 200, 200, 500, source_type, 'up', 4000)) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_equals(window.scrollY, 0); |
| }); |
| } |
| |
| function test_boundary_allows_inner(source_type) { |
| container.style.overscrollBehaviorX = 'none'; |
| container.style.overscrollBehaviorY = 'none'; |
| setUpForContainer(); |
| return smoothScroll(200, 200, 500, source_type, 'upleft', 4000) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_equals(container.scrollTop, 0); |
| assert_equals(container.scrollLeft, 0); |
| }); |
| } |
| |
| function test_boundary_on_nonscrollable_allows_propagation(source_type) { |
| non_scrollable.style.overscrollBehaviorX = 'none'; |
| non_scrollable.style.overscrollBehaviorY = 'none'; |
| window.scrollTo(0, 0); |
| return smoothScroll(200, 200, 300, source_type, 'right', 4000) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_greater_than(window.scrollX, 100);}) |
| .then( |
| smoothScroll.bind(this, 200, 200, 300, source_type, 'down', 4000)) |
| .then(waitForAnimationEnd) |
| .then(() => { |
| assert_greater_than(window.scrollY, 100); |
| }); |
| } |
| |
| const TOUCH_SOURCE_TYPE = 1; // TOUCH_INPUT from synthetic_gesture_params.h |
| const WHEEL_SOURCE_TYPE = 2; // TOUCH_INPUT from synthetic_gesture_params.h |
| promise_test(t => { |
| return test_boundary_prevents_y(WHEEL_SOURCE_TYPE); |
| }, 'overscroll-behavior-y: none should only prevent scroll propagation on y axis with: wheel.'); |
| promise_test(t => { |
| return test_boundary_prevents_x(WHEEL_SOURCE_TYPE); |
| }, 'overscroll-behavior-x: none should only prevent scroll propagation on x axis with: wheel.'); |
| promise_test(t => { |
| return test_boundary_allows_inner(WHEEL_SOURCE_TYPE); |
| }, 'overscroll-behavior should not affect scrolling inside the applied container with: wheel.'); |
| promise_test(t => { |
| return test_boundary_on_nonscrollable_allows_propagation(WHEEL_SOURCE_TYPE); |
| }, '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(TOUCH_SOURCE_TYPE); |
| }, 'overscroll-behavior-y: none should only prevent scroll propagation on y axis with: touch.'); |
| promise_test(t => { |
| return test_boundary_prevents_x(TOUCH_SOURCE_TYPE); |
| }, 'overscroll-behavior-x: none should only prevent scroll propagation on x axis with: touch.'); |
| promise_test(t => { |
| return test_boundary_on_nonscrollable_allows_propagation(TOUCH_SOURCE_TYPE); |
| }, 'overscroll-behavior on non-scrollable area should not affect scroll propagation with: touch.'); |
| } |
| </script> |