| Index: LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
|
| diff --git a/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html b/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..633eb8d62bc326e678870b4aadba4962360a5b23
|
| --- /dev/null
|
| +++ b/LayoutTests/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html
|
| @@ -0,0 +1,315 @@
|
| +<!DOCTYPE html>
|
| +<html>
|
| +<head>
|
| +<meta charset="utf-8">
|
| +<title>Scroll customization methods are called appropriately.</title>
|
| +<script src="../../../resources/testharness.js"></script>
|
| +<script src="../../../resources/testharnessreport.js"></script>
|
| +<style>
|
| +
|
| +* {
|
| + margin:0;
|
| + padding:0;
|
| +}
|
| +
|
| +*::-webkit-scrollbar {
|
| + width: 0 !important;
|
| + height: 0 !important;
|
| +}
|
| +
|
| +#a {
|
| + height:400px;
|
| + width:400px;
|
| + overflow:scroll;
|
| +}
|
| +
|
| +#b {
|
| + height:500px;
|
| + width:500px;
|
| + background-color:purple;
|
| +}
|
| +
|
| +#c {
|
| + height:300px;
|
| + width:300px;
|
| + overflow:scroll;
|
| +}
|
| +
|
| +#d {
|
| + height:400px;
|
| + width:400px;
|
| + background-color:green;
|
| +}
|
| +
|
| +body {
|
| + height:3000px;
|
| +}
|
| +
|
| +</style>
|
| +</head>
|
| +<body>
|
| +
|
| +<div id="a">
|
| +<div id="b">
|
| +<div id="c">
|
| +<div id="d">
|
| +</div>
|
| +</div>
|
| +</div>
|
| +</div>
|
| +
|
| +<script>
|
| +test(function() {
|
| + assert_true('ScrollState' in window, "'ScrollState' in window");
|
| +}, "These tests only work with scroll customization enabled.");
|
| +
|
| +var originalApplyScrolls = [];
|
| +var originalDistributeScrolls = [];
|
| +var deltas = [-85, -75, -65, -55, -45];
|
| +
|
| +var elements = [
|
| + document.getElementById("d"),
|
| + document.getElementById("c"),
|
| + document.getElementById("b"),
|
| + document.getElementById("a"),
|
| + document.scrollingElement];
|
| +
|
| +var scrollableElements = [elements[1], elements[3], elements[4]];
|
| +
|
| +document.scrollingElement.id = "scrollingElement";
|
| +
|
| +for (var i = 0; i < elements.length; ++i) {
|
| + originalApplyScrolls[i] = elements[i].applyScroll;
|
| + originalDistributeScrolls[i] = elements[i].distributeScroll;
|
| +}
|
| +
|
| +function reset() {
|
| + for (var i = 0; i < elements.length; ++i) {
|
| + var j = i;
|
| + elements[i].scrollTop = 0;
|
| + elements[i].unappliedDeltaY = [];
|
| + elements[i].distributedDeltaY = [];
|
| + elements[i].numberOfScrollBegins = 0;
|
| + elements[i].numberOfScrollEnds = 0;
|
| +
|
| + elements[i].setApplyScroll((function(originalApplyScroll, scrollState) {
|
| + originalApplyScroll.call(this, scrollState);
|
| + if (!scrollState.isEnding && !scrollState.isBeginning)
|
| + this.unappliedDeltaY.push(scrollState.deltaY);
|
| + }).bind(elements[i], originalApplyScrolls[i]));
|
| +
|
| + elements[i].setDistributeScroll((function(originalDistributeScroll, scrollState) {
|
| + if (scrollState.isBeginning)
|
| + this.numberOfScrollBegins++;
|
| + else if (scrollState.isEnding)
|
| + this.numberOfScrollEnds++;
|
| + else
|
| + this.distributedDeltaY.push(scrollState.deltaY);
|
| + originalDistributeScroll.call(this, scrollState);
|
| + }).bind(elements[i], originalDistributeScrolls[i]));
|
| + }
|
| +}
|
| +
|
| +function applyDelta(d) {
|
| + eventSender.gestureScrollBegin(10, 10);
|
| + eventSender.gestureScrollUpdate(0, d);
|
| + eventSender.gestureScrollEnd(0, 0);
|
| +}
|
| +
|
| +if ('ScrollState' in window) {
|
| + test(function() {
|
| + reset();
|
| +
|
| + // Scroll five times, with three scrollable elements.
|
| + var cScrollTop = [85, 100, 100, 100, 100];
|
| + var aScrollTop = [0, 0, 65, 100, 100];
|
| + var scrollingElementScrollTop = [0, 0, 0, 0, 45];
|
| +
|
| + for (var i = 0; i < deltas.length; ++i) {
|
| + applyDelta(deltas[i]);
|
| + assert_equals(a.scrollTop, aScrollTop[i], "For id 'a' on step " + i);
|
| + assert_equals(c.scrollTop, cScrollTop[i], "For id 'c' on step " + i);
|
| + assert_equals(document.scrollingElement.scrollTop, scrollingElementScrollTop[i], "For scrollingElement on step " + i);
|
| + }
|
| + }, "Scroll offsets are modified correctly.");
|
| +
|
| + test(function() {
|
| + reset();
|
| +
|
| + // Scroll five times, with five elements.
|
| + var unapplied = [
|
| + // d, the innermost element, never applies any scroll.
|
| + [-85, -75, -65, -55, -45],
|
| + // c applies the first two scrolls, and then hits its scroll extents.
|
| + [0, 0, -65, -55, -45],
|
| + // b doesn't scroll, and so leaves the same deltas unapplied as c.
|
| + [0, 0, -65, -55, -45],
|
| + // a hits its scroll extent on the second last step.
|
| + [0, 0, 0, 0, -45],
|
| + // The scrollingElement performs the frame scroll.
|
| + [0, 0, 0, 0, 0]];
|
| +
|
| + for (var i = 0; i < deltas.length; ++i)
|
| + applyDelta(deltas[i]);
|
| +
|
| + for (var i = 0; i < elements.length; ++i) {
|
| + var el = elements[i];
|
| + // Every element sees the same deltas being distributed.
|
| + assert_array_equals(el.distributedDeltaY, deltas, "distributed delta for " + el.id);
|
| + assert_array_equals(el.unappliedDeltaY, unapplied[i], "unapplied delta for " + el.id);
|
| + }
|
| +
|
| + // Ensure that the document leaves scroll unapplied when appropriate.
|
| + var documentUnapplied = document.scrollingElement.unappliedDeltaY;
|
| + applyDelta(-4000);
|
| + assert_equals(documentUnapplied[documentUnapplied.length - 1], 0);
|
| + applyDelta(-4000);
|
| + assert_equals(documentUnapplied[documentUnapplied.length - 1], -4000);
|
| + }, "Correct amount of delta is consumed.");
|
| +
|
| + test(function() {
|
| + reset();
|
| + // Consume one pixel of delta per call to applyScroll.
|
| + for (var i = 0; i < elements.length; ++i) {
|
| + if (scrollableElements.indexOf(elements[i]) == -1)
|
| + continue;
|
| + elements[i].setApplyScroll((function(originalApplyScroll, scrollState) {
|
| + if (scrollState.deltaY !== 0)
|
| + scrollState.consumeDelta(0, -1);
|
| + originalApplyScroll.call(this, scrollState);
|
| + }).bind(elements[i], originalApplyScrolls[i]));
|
| + }
|
| + // Scroll five times, with three scrollable elements.
|
| + // The scroll distance is decreased more the higher up the scroll chain the element is.
|
| + var cScrollTop = [85 - 1, 100, 100, 100, 100];
|
| + var aScrollTop = [0, 0, 65 - 2, 100, 100];
|
| + var scrollingElementScrollTop = [0, 0, 0, 0, 45 - 3];
|
| +
|
| + for (var i = 0; i < deltas.length; ++i) {
|
| + applyDelta(deltas[i]);
|
| + assert_equals(c.scrollTop, cScrollTop[i], "For id 'c' on step " + i);
|
| + assert_equals(a.scrollTop, aScrollTop[i], "For id 'a' on step " + i);
|
| + assert_equals(document.scrollingElement.scrollTop, scrollingElementScrollTop[i], "For scrollingElement on step " + i);
|
| + }
|
| + }, "Consuming deltas prevents scrolling.");
|
| +
|
| + test(function() {
|
| + reset();
|
| +
|
| + for (var i = 0; i < deltas.length; ++i)
|
| + applyDelta(deltas[i]);
|
| + for (var i = 0; i < elements.length; ++i) {
|
| + assert_equals(elements[i].numberOfScrollBegins, deltas.length, "Incorrect number of begin events for " + elements[i].id);
|
| + assert_equals(elements[i].numberOfScrollEnds, deltas.length, "Incorrect number of end events for " + elements[i].id);
|
| + }
|
| + }, "Correct number of scroll end and begin events observed.");
|
| +
|
| + test(function() {
|
| + // toPerform is an array of length 4, specifying whether to
|
| + // perform method |original| on |element| for scroll begin, first
|
| + // update, second update and scroll end.
|
| + function performSomeOf(element, original, toPerform) {
|
| + var updateCount = 0;
|
| + return function(scrollState) {
|
| + if (scrollState.isBeginning && scrollState.isEnding)
|
| + throw "performSomeOf requires that the scroll not both begin and end";
|
| +
|
| + var isUpdate = !scrollState.isBeginning && !scrollState.isEnding;
|
| +
|
| + if ((scrollState.isBeginning && toPerform[0]) ||
|
| + (scrollState.isEnding && toPerform[3]) ||
|
| + (isUpdate && updateCount === 0 && toPerform[1]) ||
|
| + (isUpdate && updateCount > 0 && toPerform[2])) {
|
| + original.call(element, scrollState);
|
| + }
|
| +
|
| + if (isUpdate)
|
| + updateCount++;
|
| + };
|
| + }
|
| +
|
| + // Generates an array of all arrays of booleans of length n.
|
| + // e.g. genPermutations(2) =>
|
| + // [[true, true], [true, false], [false, true], [false, false]].
|
| + function genPermutations(n) {
|
| + if (n === 0)
|
| + return [[]];
|
| + var perms = genPermutations(n - 1);
|
| + return perms.map(function(x) {
|
| + return x.concat([true]);
|
| + }).concat(perms.map(function(x) {
|
| + return x.concat([false]);
|
| + }));
|
| + }
|
| +
|
| + function applyDeltaWithTwoUpdates(d) {
|
| + eventSender.gestureScrollBegin(10, 10);
|
| + eventSender.gestureScrollUpdate(0, d/2);
|
| + eventSender.gestureScrollUpdate(0, d/2);
|
| + eventSender.gestureScrollEnd(0, 0);
|
| + }
|
| +
|
| + var scroller = document.scrollingElement;
|
| +
|
| + for (applyScrollPermutation of genPermutations(4)) {
|
| + reset();
|
| + scroller.setApplyScroll(performSomeOf(scroller, scroller.applyScroll, applyScrollPermutation));
|
| +
|
| + for (distributeScrollPermutation of genPermutations(4)) {
|
| + scroller.setDistributeScroll(performSomeOf(scroller, scroller.distributeScroll, distributeScrollPermutation));
|
| + applyDeltaWithTwoUpdates(-50);
|
| + }
|
| + }
|
| + }, "Ensure that any subset of the native scroll methods can be called, without crashing");
|
| +
|
| + {
|
| + // NOTE - this async test needs to be run last, as it shares state with the
|
| + // other tests. If other tests are run after it, they'll modify the state
|
| + // while this test is still running.
|
| + var flingTest = async_test("Touchscreen fling doesn't propagate.");
|
| + reset();
|
| +
|
| + function assertScrollTops(cTop, aTop, scrollingElementTop, step) {
|
| + assert_equals(c.scrollTop, cTop, "For id 'c' on step " + step);
|
| + assert_equals(a.scrollTop, aTop, "For id 'a' on step " + step);
|
| + assert_equals(document.scrollingElement.scrollTop, scrollingElementTop, "For scrollingElement on step " + step);
|
| + };
|
| +
|
| + var frame_actions = [
|
| + function() {
|
| + eventSender.gestureFlingStart(10, 10, -1000000, -1000000, "touchscreen");
|
| + },
|
| + flingTest.step_func(function() {
|
| + assertScrollTops(0, 0, 0, 1);
|
| + }),
|
| + flingTest.step_func(function() {
|
| + assertScrollTops(100, 0, 0, 2);
|
| + }),
|
| + flingTest.step_func(function() {
|
| + assertScrollTops(100, 0, 0, 3);
|
| + }),
|
| + flingTest.step_func(function() {
|
| + assertScrollTops(100, 0, 0, 4);
|
| + flingTest.done();
|
| + })
|
| + ]
|
| +
|
| + function executeFrameActions(frame_actions) {
|
| + var frame = 0;
|
| + function raf() {
|
| + frame_actions[frame]();
|
| + frame++;
|
| + if (frame >= frame_actions.length)
|
| + return;
|
| + window.requestAnimationFrame(raf);
|
| + }
|
| + window.requestAnimationFrame(raf);
|
| + }
|
| +
|
| + executeFrameActions(frame_actions);
|
| + }
|
| +}
|
| +
|
| +</script>
|
| +</body>
|
| +</html>
|
|
|