toolkit/content/tests/chrome/test_arrowpanel.xul
author Neil Deakin <neil@mozilla.com>
Mon, 16 Jun 2014 14:43:07 -0400
changeset 209717 0e9d11e5302ac3a421a0de44283b47b9465fb42e
parent 200987 77aff162aa0cae1c6066b1d29c59bd9bd24fa09b
child 214726 f32dd267971e261704d3cd9a61edb9dd2cfc79b7
permissions -rw-r--r--
Bug 994117, delay popupshown event until after the opening transition has finished, if one exists, which also fixes the issue causing bug 989991, so enable the animation on the main panel, r=neil

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>

<window title="Arrow Panels"
        style="padding: 10px;"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>

<stack flex="1">
  <label id="topleft" value="Top Left Corner" left="15" top="15"/>
  <label id="topright" value="Top Right" right="15" top="15"/>
  <label id="bottomleft" value="Bottom Left Corner" left="15" bottom="15"/>
  <label id="bottomright" value="Bottom Right" right="15" bottom="15"/>
  <!-- Our SimpleTest/TestRunner.js runs tests inside an iframe which sizes are W=500 H=300.
       'left' and 'top' values need to be set so that the panel (popup) has enough room to display on its 4 sides. -->
  <label id="middle" value="+/- Centered" left="225" top="135"/>
  <iframe id="frame" type="content"
          src="data:text/html,&lt;input id='input'&gt;" width="100" height="100" left="225" top="120"/>
</stack>

<panel id="panel" type="arrow" animate="false"
       onpopupshown="checkPanelPosition(this)" onpopuphidden="runNextTest.next()">
  <label id="panellabel" value="This is some text..." height="65"/>
</panel>

<panel id="bigpanel" type="arrow" animate="false"
       onpopupshown="checkBigPanel(this)" onpopuphidden="runNextTest.next()">
  <button label="This is some text..." height="3000"/>
</panel>

<panel id="animatepanel" type="arrow"
       onpopupshown="animatedPopupShown = true;"
       onpopuphidden="animatedPopupHidden = true; runNextTest.next();">
  <label value="Animate Closed" height="40"/>
</panel>

<script type="application/javascript">
<![CDATA[

SimpleTest.waitForExplicitFinish();

var expectedAnchor = null;
var expectedSide = "", expectedAnchorEdge = "", expectedPack = "", expectedAlignment = "";
var zoomFactor = 1;
var animatedPopupShown = false;
var animatedPopupHidden = false;
var runNextTest;

function startTest()
{
  runNextTest = nextTest();
  runNextTest.next();
}

function nextTest()
{
  var panel = $("panel");

  function openPopup(position, anchor, expected, anchorEdge, pack, alignment)
  {
    expectedAnchor = anchor instanceof Node ? anchor : $(anchor);
    expectedSide = expected;
    expectedAnchorEdge = anchorEdge;
    expectedPack = pack;
    expectedAlignment = alignment == undefined ? position : alignment;

    panel.removeAttribute("side");
    panel.openPopup(expectedAnchor, position, 0, 0, false, false, null);
  }

  for (var iter = 0; iter < 2; iter++) {
    openPopup("after_start", "topleft", "top", "left", "start");
    yield;
    openPopup("after_start", "bottomleft", "bottom", "left", "start", "before_start");
    yield;
    openPopup("before_start", "topleft", "top", "left", "start", "after_start");
    yield;
    openPopup("before_start", "bottomleft", "bottom", "left", "start");
    yield;
    openPopup("after_start", "middle", "top", "left", "start");
    yield;
    openPopup("before_start", "middle", "bottom", "left", "start");
    yield;

    openPopup("after_start", "topright", "top", "right", "end", "after_end");
    yield;
    openPopup("after_start", "bottomright", "bottom", "right", "end", "before_end");
    yield;
    openPopup("before_start", "topright", "top", "right", "end", "after_end");
    yield;
    openPopup("before_start", "bottomright", "bottom", "right", "end", "before_end");
    yield;

    openPopup("after_end", "middle", "top", "right", "end");
    yield;
    openPopup("before_end", "middle", "bottom", "right", "end");
    yield;

    openPopup("start_before", "topleft", "left", "top", "start", "end_before");
    yield;
    openPopup("start_before", "topright", "right", "top", "start");
    yield;
    openPopup("end_before", "topleft", "left", "top", "start");
    yield;
    openPopup("end_before", "topright", "right", "top", "start", "start_before");
    yield;
    openPopup("start_before", "middle", "right", "top", "start");
    yield;
    openPopup("end_before", "middle", "left", "top", "start");
    yield;

    openPopup("start_before", "bottomleft", "left", "bottom", "end", "end_after");
    yield;
    openPopup("start_before", "bottomright", "right", "bottom", "end", "start_after");
    yield;
    openPopup("end_before", "bottomleft", "left", "bottom", "end", "end_after");
    yield;
    openPopup("end_before", "bottomright", "right", "bottom", "end", "start_after");
    yield;

    openPopup("start_after", "middle", "right", "bottom", "end");
    yield;
    openPopup("end_after", "middle", "left", "bottom", "end");
    yield;

    openPopup("topcenter bottomleft", "bottomleft", "bottom", "center left", "start", "before_start");
    yield;
    openPopup("bottomcenter topleft", "topleft", "top", "center left", "start", "after_start");
    yield;
    openPopup("topcenter bottomright", "bottomright", "bottom", "center right", "end", "before_end");
    yield;
    openPopup("bottomcenter topright", "topright", "top", "center right", "end", "after_end");
    yield;
    openPopup("topcenter bottomleft", "middle", "bottom", "center left", "start", "before_start");
    yield;
    openPopup("bottomcenter topleft", "middle", "top", "center left", "start", "after_start");
    yield;

    openPopup("leftcenter topright", "middle", "right", "center top", "start", "start_before");
    yield;
    openPopup("rightcenter bottomleft", "middle", "left", "center bottom", "end", "end_after");
    yield;

/*
    XXXndeakin disable these parts of the test which often cause problems, see bug 626563

    openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
    yield;

    setScale(frames[0], 1.5);
    openPopup("after_start", frames[0].document.getElementById("input"), "top", "left", "start");
    yield;

    setScale(frames[0], 2.5);
    openPopup("before_start", frames[0].document.getElementById("input"), "bottom", "left", "start");
    yield;

    setScale(frames[0], 1);
*/

    $("bigpanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
    yield;

    // switch to rtl mode
    document.documentElement.style.direction = "rtl";
    $("topleft").setAttribute("right", "15");
    $("topright").setAttribute("left", "15");
    $("bottomleft").setAttribute("right", "15");
    $("bottomright").setAttribute("left", "15");
    $("topleft").removeAttribute("left");
    $("topright").removeAttribute("right");
    $("bottomleft").removeAttribute("left");
    $("bottomright").removeAttribute("right");
  }

  // Test that a transition occurs when opening or closing the popup. The transition is
  // disabled on Linux.
  if (navigator.platform.indexOf("Linux") == -1) {
    var transitions = 0;
    function transitionEnded(event) {
      transitions++;
      // Two properties transition so continue on the second one finishing.
      if (!(transitions % 2)) {
        ok(animatedPopupShown, "popupshown now fired")
        SimpleTest.executeSoon(() => runNextTest.next());
      }
      else {
        ok(!animatedPopupShown, "popupshown not fired yet")
      }
    }

    // Check that the transition occurs for an arrow panel with animate="true"
    window.addEventListener("transitionend", transitionEnded, false);
    $("animatepanel").openPopup($("topleft"), "after_start", 0, 0, false, false, null, "start");
    yield;
    window.removeEventListener("transitionend", transitionEnded, false);

    synthesizeKey("VK_ESCAPE", { });
    ok(!animatedPopupHidden, "animated popup not hidden yet");
    yield;
  }

  SimpleTest.finish()
  yield;
}

function setScale(win, scale)
{
  var wn = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
              .getInterface(Components.interfaces.nsIWebNavigation);
  var shell = wn.QueryInterface(Components.interfaces.nsIDocShell);
  var docViewer = shell.contentViewer.QueryInterface(Components.interfaces.nsIMarkupDocumentViewer);
  docViewer.fullZoom = scale;
  zoomFactor = scale;
}

function checkPanelPosition(panel)
{
  let anchor = panel.anchorNode;
  let adj = 0, hwinpos = 0, vwinpos = 0;
  if (anchor.ownerDocument != document) {
    var framerect = anchor.ownerDocument.defaultView.frameElement.getBoundingClientRect();
    hwinpos = framerect.left;
    vwinpos = framerect.top;
  }

  // Positions are reversed in rtl yet the coordinates used in the computations
  // are not, so flip the expected label side and anchor edge.
  var isRTL = (window.getComputedStyle(panel).direction == "rtl");
  if (isRTL) {
    var flipLeftRight = function (val) val == "left" ? "right" : "left";
    expectedAnchorEdge = expectedAnchorEdge.replace(/(left|right)/, flipLeftRight);
    expectedSide = expectedSide.replace(/(left|right)/, flipLeftRight);
  }

  var panelRect = panel.getBoundingClientRect();
  var anchorRect = anchor.getBoundingClientRect();
  var labelBO = $("panellabel").boxObject;
  var labelRect = { top: labelBO.y,
                    left: labelBO.x,
                    bottom: labelBO.y + labelBO.height,
                    right: labelBO.x + labelBO.width };
  switch (expectedSide) {
    case "top":
      ok(labelRect.top > vwinpos + anchorRect.bottom * zoomFactor + 5, "panel label is below");
      break;
    case "bottom":
      ok(labelRect.bottom < vwinpos + anchorRect.top * zoomFactor - 5, "panel label is above");
      break;
    case "left":
      ok(labelRect.left > hwinpos + anchorRect.right * zoomFactor + 5, "panel label is right");
      break;
    case "right":
      ok(labelRect.right < hwinpos + anchorRect.left * zoomFactor - 5, "panel label is left");
      break;
  }

  let iscentered = false;
  if (expectedAnchorEdge.indexOf("center ") == 0) {
    expectedAnchorEdge = expectedAnchorEdge.substring(7);
    iscentered = true;
  }

  switch (expectedAnchorEdge) {
    case "top":
      adj = vwinpos + parseInt(getComputedStyle(panel, "").marginTop);
      if (iscentered)
        adj += Math.round(anchorRect.height) / 2;
      isWithinHalfPixel(panelRect.top, anchorRect.top * zoomFactor + adj, "anchored on top");
      break;
    case "bottom":
      adj = vwinpos + parseInt(getComputedStyle(panel, "").marginBottom);
      if (iscentered)
        adj += Math.round(anchorRect.height) / 2;
      isWithinHalfPixel(panelRect.bottom, anchorRect.bottom * zoomFactor - adj, "anchored on bottom");
      break;
    case "left":
      adj = hwinpos + parseInt(getComputedStyle(panel, "").marginLeft);
      if (iscentered)
        adj += Math.round(anchorRect.width) / 2;
      isWithinHalfPixel(panelRect.left, anchorRect.left * zoomFactor + adj, "anchored on left ");
      break;
    case "right":
      adj = hwinpos + parseInt(getComputedStyle(panel, "").marginRight);
      if (iscentered)
        adj += Math.round(anchorRect.width) / 2;
      isWithinHalfPixel(panelRect.right, anchorRect.right * zoomFactor - adj, "anchored on right");
      break;
  }

  is(anchor, expectedAnchor, "anchor");

  var arrow = document.getAnonymousElementByAttribute(panel, "anonid", "arrow");
  is(arrow.getAttribute("side"), expectedSide, "panel arrow side");
  is(arrow.hidden, false, "panel hidden");
  is(arrow.parentNode.pack, expectedPack, "panel arrow pack");
  is(panel.alignmentPosition, expectedAlignment, "panel alignmentPosition");

  panel.hidePopup();
}

function isWithinHalfPixel(a, b, desc)
{
  ok(Math.abs(a - b) <= 0.5, desc);
}

function checkBigPanel(panel)
{
  ok(panel.firstChild.getBoundingClientRect().height < 2800, "big panel height");
  panel.hidePopup();
}

SimpleTest.waitForFocus(startTest);

]]>
</script>

<body xmlns="http://www.w3.org/1999/xhtml"/>

</window>