/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/* import-globals-from ../../../dom/animation/test/testcommon.js */
Services.scriptloader.loadSubScript(
  "chrome://mochitests/content/tests/dom/animation/test/testcommon.js",
  this
);

add_task(async () => {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["layout.animation.prerender.partial", true],
      ["layout.animation.prerender.viewport-ratio-limit", 1.125],
    ],
  });

  let navBar = document.getElementById("nav-bar");

  const anchor = document.createXULElement("toolbarbutton");
  anchor.classList.add("toolbarbutton-1", "chromeclass-toolbar-additional");
  navBar.appendChild(anchor);

  // Prepare a popup panel.
  const panel = document.createXULElement("panel");
  panel.setAttribute("noautohide", true);
  navBar.appendChild(panel);

  // Add a overflow:scroll container to avoid expanding the popup window size.
  const container = document.createElement("div");
  container.style = "width: 100px; height: 100px; overflow: scroll;";

  // Looks like in popup window wider elements in the overflow:scroll container
  // are still affecting the viewport size of the popup content, for example,
  // if we specify "witdh: 800px" here, this element is not going to be partial-
  // prerendered, it will be fully prerendered, so we use vertically overflowed
  // element here.
  const target = document.createElement("div");
  target.style = "width: 100px; height: 800px;";

  container.appendChild(target);
  panel.appendChild(container);

  registerCleanupFunction(() => {
    panel.remove();
    anchor.remove();
  });

  panel.openPopup(anchor);

  // Start a transform transition with a 1s delay step-start function so that
  // we can ensure that
  // 1) when the target element is initially composited on the compositor the
  //    transition hasn't yet started, thus no jank happens
  // 2) when the transition starts on the compositor thread, it causes a jank
  //    so that it will report back to the main-thread
  target.style.transition = "transform 100s step-start 1s";
  getComputedStyle(target);
  const startTransition = new Promise(resolve => {
    target.addEventListener("transitionstart", resolve);
  });
  target.style.transform = "translateY(-130px)";
  const transition = target.getAnimations()[0];

  // Wait for the transition start.
  await startTransition;

  // Make sure it's running on the compositor.
  Assert.ok(
    transition.isRunningOnCompositor,
    "The transition should be running on the compositor thread"
  );

  // Collect restyling markers in 5 frames.
  const markers = await observeStylingInTargetWindow(panel.ownerGlobal, 5);

  // On non WebRender we observe two restyling markers because we get the second
  // jank report from the compositor thread before a new pre-rendered result,
  // which was triggered by the first jank report, reached to the compositor
  // thread. So we allow one or two makers here.
  // NOTE: Since we wrap the target element in overflow:scroll container, we
  // might see an additional restyling marker triggered by
  // KeyframeEffect::OverflowRegionRefreshInterval (200ms) on very slow
  // platforms (e.g. TSAN builds), if it happens we should allow the additional
  // restyling here.
  Assert.greaterOrEqual(markers.length, 1);
  Assert.lessOrEqual(markers.length, 2);
});
