author Jan Henning <>
Fri, 11 Jan 2019 19:50:09 +0000
changeset 453553 39207d39e5c2
parent 453548 7b00521b6f31
child 453555 a99bf382e5f7
permissions -rw-r--r--
Bug 1498812 - Part 9: Switch session store/session history to use visual viewport for scroll position tracking. r=mikedeboer,snorp For simplicity's sake, for now we keep storing only one scroll position per history entry (bug 1499210), so if we have to choose between the layout and the visual viewport, the latter is a vastly better choice, as it more accurately represents the scroll position as perceived by the user, especially when the page has been pinch-zoomed. This also means that instead of the normal scroll events, the session store now has to listen for the corresponding events specific to the visual viewport. We also extend the scroll position test to check that the scroll position isn't just properly saved, but also actually properly restored in practice as well. We only add this test now instead of already adding it beforehand like we did with the rest of the test - to avoid having to temporarily extend the checkScroll() helper function to deal with todo()/todo_is etc. - because getting that part of the test to complete without timing out (which would be one of its natural failure modes, because the expected events would be missing) would require faking even more scroll events - because we already have the todo() tests that are telling us the we didn't *store* any scroll position in the first place, so there's no point in trying to actually restore anything For the GeckoView saveAndRestoreState test, we now spin the event loop once before setting the scroll position in order to give APZ opportunity to settle down after the initial page load. Differential Revision:

  <meta charset="utf-8">
  <title>Various scroll position tests for the mobile session store, dealing specifically with the Visual Viewport</title>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/AddTask.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
  <script type="application/javascript" src="head.js"></script>
  <script type="application/javascript" src="head_scroll.js"></script>
  <script type="application/javascript" src="apz_test_utils.js"></script>
  <script type="application/javascript" src="apz_test_native_event_utils.js"></script>
  <script type="application/javascript">
  /* import-globals-from ../../../../../gfx/layers/apz/test/mochitest/apz_test_utils.js */
  /* import-globals-from ../../../../../gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js */

  /** Tests for Bug 1498812 **/

  "use strict";


  // The chrome window and friends.
  let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
  let BrowserApp = chromeWin.BrowserApp;

  const BASE = "";
  // This is a plain desktop page without any meta viewport tags,
  // so the layout viewport will always fill the full page width.
  const URL = BASE + "basic_article.html";
  // A mobile page using width=device-width, which leads to the same result.
  const URL2 = BASE + "basic_article_mobile.html";

  async function scrollRight(window) {
    // This listener will trigger the test to continue once APZ is done with
    // processing the scroll.
    let transformEnd = promiseNotification("APZ:TransformEnd");

    let scroll = [
        [ { x: 125, y: 100 } ],
        [ { x: 120, y: 100 } ],
        [ { x: 115, y: 100 } ],
        [ { x: 110, y: 100 } ],
        [ { x: 105, y: 100 } ],
        [ { x: 100, y: 100 } ],

    let touchIds = [0];
    let doScroll = synthesizeNativeTouchSequences(document.body, scroll, null, touchIds);
    while (!;

    await transformEnd;

    await promiseApzRepaintsFlushed(window);

  // Track the tabs where the tests are happening.
  let tabScroll;

  function cleanupTabs() {
    if (tabScroll) {
      tabScroll = null;

  SimpleTest.registerCleanupFunction(function() {

  let ss = Cc[";1"].getService(Ci.nsISessionStore);

  add_task(async function test_sessionStoreScrollPositionVisualViewport() {
    let zoomIn = {x: 0, y: 0, zoom: 4 };
    let scrollPos1, scrollPos2;
    // Creates a tab, sets a scroll position and zoom level and closes the tab.
    async function createAndRemoveTab() {
        // Create a new tab.
        tabScroll = BrowserApp.addTab(URL);
        let browser = tabScroll.browser;
        await promiseBrowserEvent(browser, "pageshow");

        // Zoom in, so we can scroll to the right.
        let scrolled = promiseTabEvent(browser, "SSTabScrollCaptured");
        setScrollPosition(browser, zoomIn);
        await scrolled;

        // Check that we've actually zoomed.
        checkScroll(browser, zoomIn);

        scrolled = promiseTabEvent(browser, "SSTabScrollCaptured");
        await scrollRight(browser.contentWindow);
        await scrolled;

        scrollPos1 = getScrollPosition(browser);
        isnot(scrollPos1.x, 0, "we should be scrolled to the right");
        is(scrollPos1.y, 0, "we scrolled horizontally");

        // Navigate to a different page and scroll/zoom there as well.
        await promiseBrowserEvent(browser, "pageshow");

        scrolled = promiseTabEvent(browser, "SSTabScrollCaptured");
        setScrollPosition(browser, zoomIn);
        await scrolled;
        checkScroll(browser, zoomIn);

        scrolled = promiseTabEvent(browser, "SSTabScrollCaptured");
        await scrollRight(browser.contentWindow);
        await scrolled;

        scrollPos2 = getScrollPosition(browser);
        isnot(scrollPos2.x, 0, "we should be scrolled to the right");
        is(scrollPos2.y, 0, "we scrolled horizontally");

        // Remove the tab.
        let closed = promiseTabEvent(browser, "SSTabCloseProcessed");
        await closed;

    await createAndRemoveTab();

    // Check the live scroll data for the current history entry...
    let tabData = ss.getClosedTabs(chromeWin)[0];
    let {scrolldata} = tabData;
    is(scrolldata.scroll, getScrollString(scrollPos2), "stored scroll position is correct");
    ok(fuzzyEquals(scrolldata.zoom.resolution, scrollPos2.zoom), "stored zoom level is correct");

    // ... and the presState from the previous history entry.
    let {index} = tabData;
    index -= 1; // session history uses 1-based index
    let {entries} = tabData;
    let prevPage = entries[index - 1];
    todo(prevPage.presState, "presState exists");
    if (prevPage.presState) {
      let presState = prevPage.presState[0];
      // The presState operates in app units, while all other scroll positions
      // in JS-land use CSS pixels.
      presState = presStateToCSSPx(presState);
      todo_is(presState.scroll, getScrollString(scrollPos1), "stored scroll position for previous page is correct");
      ok(fuzzyEquals(presState.res, scrollPos1.zoom), "stored zoom level for previous page is correct");

    // Restore the closed tab.
    let browser = ss.undoCloseTab(chromeWin, tabData);
    tabScroll = BrowserApp.getTabForBrowser(browser);
    let pageshow = promiseBrowserEvent(browser, "pageshow");
    let scroll = promiseBrowserEvent(browser, "mozvisualscroll",
                                     { mozSystemGroup: true });
    await pageshow;
    await scroll;

    // Check the scroll position and zoom level.
    checkScroll(browser, scrollPos2);

    // Remove the tab.

<a target="_blank" href="">Mozilla Bug 1498812</a>
<p id="display"></p>
<div id="content" style="display: none">

<pre id="test">