<!DOCTYPE HTML> <html> <head> <title>Test for scroll snapping</title> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <p id="display"></p> <div id="sc" style="margin: 0px; padding: 0px; overflow: scroll; width:250px; height: 250px;"> <div id="sd" style="margin: 0px; padding: 0px; width: 1250px; height: 1250px;"></div> </div> <pre id="test"> <script class="testbody" type="text/javascript"> var runtime = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"] .getService(SpecialPowers.Ci.nsIXULRuntime); var isMac = navigator.platform.indexOf("Mac") != -1; var isGtk = runtime.widgetToolkit.indexOf("gtk") != -1; var isWin = navigator.platform.indexOf("Win") != -1; var isSN = /mac os x 10\.6/.test(navigator.userAgent.toLowerCase()); // Half of the scrollbar control width, in CSS pixels var scrollbarOffset = isWin ? 8 : 5; // OSX 10.6 scroll bar thumbs are off-center due to the bundling of buttons on one end // of the scroll bar frame. var scrollbarCenter = isSN ? 100 : 125; var testCases = [ { "description" : "Drag scrollbar left, expect scroll snapping.", "snapCoord" : "500px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : scrollbarCenter, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : -10, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Drag scrollbar right, expect scroll snapping.", "snapCoord" : "500px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : scrollbarCenter, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 10, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Drag scrollbar up, expect scroll snapping.", "snapCoord" : "500px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : scrollbarCenter }, "mouseOffset" : { "x" : 0, "y" : -10 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Drag scrollbar down, expect scroll snapping.", "snapCoord" : "500px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : scrollbarCenter }, "mouseOffset" : { "x" : 0, "y" : 10 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Page scrollbar left, expect scroll snapping.", "snapCoord" : "500px 500px, 1000px 500px", "startScroll" : { "x" : 1000, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 50, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Page scrollbar right, expect scroll snapping.", "snapCoord" : "500px 500px, 0px 500px", "startScroll" : { "x" : 0, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 200, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Page scrollbar up, expect scroll snapping.", "snapCoord" : "500px 500px, 500px 1000px", "startScroll" : { "x" : 500, "y" : 1000 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : 50 }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Page scrollbar down, expect scroll snapping.", "snapCoord" : "500px 500px, 500px 0px", "startScroll" : { "x" : 500, "y" : 0 }, "endScroll" : { "x" : 500, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : 200 }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : true, "runGtk" : true, "runWin" : true }, { "description" : "Click scrollbar left button, expect scroll snapping.", "snapCoord" : "50px 500px, 250px 500px, 500px 500px, 750px 500px, 950px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 250, "y" : 500 }, "mousePosition" : { "x" : scrollbarOffset, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Hold scrollbar left button until repeating, expect scroll snapping.", "snapCoord" : "50px 500px, 500px 500px, 950px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 50, "y" : 500 }, "mousePosition" : { "x" : scrollbarOffset, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "500", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Click scrollbar right button, expect scroll snapping.", "snapCoord" : "50px 500px, 250px 500px, 500px 500px, 750px 500px, 950px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 750, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset * 3, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Hold scrollbar right button until repeating, expect scroll snapping.", "snapCoord" : "50px 500px, 500px 500px, 950px 500px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 950, "y" : 500 }, "mousePosition" : { "x" : 250 - scrollbarOffset * 3, "y" : 250 - scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "500", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Click scrollbar up button, expect scroll snapping.", "snapCoord" : "500px 50px, 500px 250px, 500px 500px, 500px 750px, 500px 950px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 250 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Hold scrollbar up button until repeating, expect scroll snapping.", "snapCoord" : "500px 50px, 500px 500px, 500px 950px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 50 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : scrollbarOffset }, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "500", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Click scrollbar down button, expect scroll snapping.", "snapCoord" : "500px 50px, 500px 250px, 500px 500px, 500px 750px, 500px 950px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 750 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : 250 - scrollbarOffset * 3}, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "0", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, { "description" : "Hold scrollbar down button until repeating, expect scroll snapping.", "snapCoord" : "500px 50px, 500px 500px, 500px 950px", "startScroll" : { "x" : 500, "y" : 500 }, "endScroll" : { "x" : 500, "y" : 950 }, "mousePosition" : { "x" : 250 - scrollbarOffset, "y" : 250 - scrollbarOffset * 3}, "mouseOffset" : { "x" : 0, "y" : 0 }, "duration" : "500", "runMac" : false, // OSX does not have have line-scroll buttons "runGtk" : false, // Some GTK themes may not have scroll buttons "runWin" : true }, ]; var step = 0; var sc; // Scroll Container var sd; // Scrolled Div var lastScrollTop; var lastScrollLeft; var stopFrameCount; var winUtils = SpecialPowers.DOMWindowUtils; function doTest() { var testCase = testCases[step]; stopFrameCount = 0; lastScrollTop = sc.scrollTop; lastScrollLeft = sc.scrollLeft; sc.scrollTo(testCase.startScroll.x, testCase.startScroll.y); sc.style.scrollSnapType = "mandatory"; sd.style.scrollSnapCoordinate = testCase.snapCoord; synthesizeMouse(sc, testCase.mousePosition.x, testCase.mousePosition.y, { type: "mousedown" }); synthesizeMouse(sc, testCase.mousePosition.x + testCase.mouseOffset.x, testCase.mousePosition.y + testCase.mouseOffset.y, { type: "mousemove" }); stopFrameCount = 0; waitForScrollStart(); } function waitForScrollStart() { // Wait for up to 30 frames for scrolling to start var testCase = testCases[step]; if (testCase.startScroll.y != sc.scrollTop || testCase.startScroll.x != sc.scrollLeft || ++stopFrameCount < 30) { window.requestAnimationFrame(doMouseUp); } else { window.requestAnimationFrame(waitForScrollStart); } } function doMouseUp() { var testCase = testCases[step]; isnot("(" + sc.scrollLeft + "," + sc.scrollTop + ")", "(" + testCase.startScroll.x +"," + testCase.startScroll.y + ")", "Step " + step + ": Synthesized mouse events move scroll position. (" + testCase.description + ")"); window.setTimeout(function() { synthesizeMouse(sc, testCase.mousePosition.x + testCase.mouseOffset.x, testCase.mousePosition.y + testCase.mouseOffset.y, { type: "mouseup" }); stopFrameCount = 0; window.requestAnimationFrame(waitForScrollStop); }, testCase.duration); } function waitForScrollStop() { if (stopFrameCount > 30) { // We have the same position for 30 consecutive frames -- we are stopped verifyTest(); } else { // Still moving if (lastScrollTop == sc.scrollTop && lastScrollLeft == sc.scrollLeft) { stopFrameCount++; } else { stopFrameCount = 0; lastScrollTop = sc.scrollTop; lastScrollLeft = sc.scrollLeft; } window.requestAnimationFrame(waitForScrollStop); } } function verifyTest() { // Test ended, check if scroll position matches expected position var testCase = testCases[step]; is("(" + sc.scrollLeft + "," + sc.scrollTop + ")", "(" + testCase.endScroll.x +"," + testCase.endScroll.y + ")", "Step " + step + ": " + testCase.description); // Find next test to run while (true) { if (++step == testCases.length) { SimpleTest.finish(); break; } else { testCase = testCases[step]; if ((testCase.runGtk && isGtk) || (testCase.runMac && isMac) || (testCase.runWin && isWin)) { doTest(); break; } } } } SimpleTest.waitForExplicitFinish(); SimpleTest.requestFlakyTimeout("Delays added to allow synthesized mouse " + "events to trigger scrollbar repeating scrolls."); addLoadEvent(function() { sc = document.getElementById("sc"); sd = document.getElementById("sd"); SpecialPowers.pushPrefEnv({ "set": [["layout.css.scroll-snap.enabled", true], ["layout.css.scroll-snap.proximity-threshold", 100]]}, doTest); }); </script> </pre> </body> </html>