layout/style/test/test_transitions_per_property.html
author L. David Baron <dbaron@dbaron.org>
Fri, 11 Dec 2009 08:13:19 -0800
changeset 35570 9553ddacda66a05dbf4e3dbcdd90bdde54ff2f3e
parent 35569 fa46cff7f78d136e9e5335e35b1def2329663a08
child 36525 bfe4de8f0428de92bdd54c994b8fa321e05fb613
permissions -rw-r--r--
Add support for animation of border-spacing and -moz-transform-origin. (Bug 524861) r=bzbarsky

<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=435441
-->
<head>
  <title>Test for Bug 435441</title>
  <script type="application/javascript" src="/MochiKit/packed.js"></script>
  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="property_database.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <style type="text/css">

  #display > p { margin-top: 0; margin-bottom: 0; }

  </style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=435441">Mozilla Bug 435441</a>

<!--
  fixed-height container so percentage heights compute to different
  (i.e., nonzero) values
  fixed-width container so that percentages for margin-top and
  margin-bottom are all relative to the same size container (rather than
  one that depends on whether we're tall enough to need a scrollbar)
  -->
<div style="height: 50px; width: 300px">

<div id="display">

</div>
</div>
<pre id="test">
<script type="application/javascript">

/** Test for Bug 435441 **/

function has_num(str)
{
    return !!String(str).match(/^([\d.]+)/);
}

function any_unit_to_num(str)
{
    return Number(String(str).match(/^([\d.]+)/)[1]);
}

var supported_properties = {
    "-moz-border-radius-bottomleft": [ test_radius_transition ],
    "-moz-border-radius-bottomright": [ test_radius_transition ],
    "-moz-border-radius-topleft": [ test_radius_transition ],
    "-moz-border-radius-topright": [ test_radius_transition ],
    "-moz-box-flex": [ test_float_zeroToOne_transition,
                       test_float_aboveOne_transition ],
    "-moz-box-shadow": [ test_shadow_transition ],
    "-moz-column-count": [ test_pos_integer_or_auto_transition ],
    "-moz-column-gap": [ test_length_transition ],
    "-moz-column-rule-color": [ test_color_transition ],
    "-moz-column-rule-width": [ test_length_transition ],
    "-moz-column-width": [ test_length_transition ],
    "-moz-outline-radius-bottomleft": [ test_radius_transition ],
    "-moz-outline-radius-bottomright": [ test_radius_transition ],
    "-moz-outline-radius-topleft": [ test_radius_transition ],
    "-moz-outline-radius-topright": [ test_radius_transition ],
    "-moz-transform-origin": [ test_length_pair_transition,
                               test_length_percent_pair_transition ],
    "background-color": [ test_color_transition ],
    "border-bottom-color": [ test_color_transition ],
    "border-bottom-width": [ test_length_transition ],
    "border-left-color": [ test_color_transition ],
    "border-left-width": [ test_length_transition ],
    "border-right-color": [ test_color_transition ],
    "border-right-width": [ test_length_transition ],
    "border-spacing": [ test_length_pair_transition ],
    "border-top-color": [ test_color_transition ],
    "border-top-width": [ test_length_transition ],
    "bottom": [ test_length_transition, test_percent_transition ],
    "color": [ test_color_transition ],
    "fill": [ test_color_transition ],
    "fill-opacity" : [ test_float_zeroToOne_transition ],
    "flood-color": [ test_color_transition ],
    "flood-opacity" : [ test_float_zeroToOne_transition ],
    "font-size": [ test_length_transition, test_percent_transition ],
    "font-size-adjust": [ test_float_zeroToOne_transition,
                          test_float_aboveOne_transition ],
    "font-stretch": [ test_font_stretch ],
    "font-weight": [ test_font_weight ],
    "height": [ test_length_transition, test_percent_transition ],
    "left": [ test_length_transition, test_percent_transition ],
    "letter-spacing": [ test_length_transition ],
    "lighting-color": [ test_color_transition ],
    "line-height": [ test_length_transition, test_percent_transition ],
    "margin-bottom": [ test_length_transition, test_percent_transition ],
    "margin-left": [ test_length_transition, test_percent_transition ],
    "margin-right": [ test_length_transition, test_percent_transition ],
    "margin-top": [ test_length_transition, test_percent_transition ],
    "marker-offset": [ test_length_transition ],
    "max-height": [ test_length_transition, test_percent_transition ],
    "max-width": [ test_length_transition, test_percent_transition ],
    "min-height": [ test_length_transition, test_percent_transition ],
    "min-width": [ test_length_transition, test_percent_transition ],
    "opacity" : [ test_float_zeroToOne_transition ],
    "outline-color": [ test_color_transition ],
    "outline-offset": [ test_length_transition ],
    "outline-width": [ test_length_transition ],
    "padding-bottom": [ test_length_transition, test_percent_transition ],
    "padding-left": [ test_length_transition, test_percent_transition ],
    "padding-right": [ test_length_transition, test_percent_transition ],
    "padding-top": [ test_length_transition, test_percent_transition ],
    "right": [ test_length_transition, test_percent_transition ],
    "stop-color": [ test_color_transition ],
    "stop-opacity" : [ test_float_zeroToOne_transition ],
    "stroke": [ test_color_transition ],
    "stroke-dasharray": [ test_dasharray_transition ],
    "stroke-dashoffset": [ test_length_transition, test_percent_transition ],
    "stroke-miterlimit": [ test_float_aboveOne_transition ],
    "stroke-opacity" : [ test_float_zeroToOne_transition ],
    "stroke-width": [ test_length_transition, test_percent_transition ],
    "text-indent": [ test_length_transition, test_percent_transition ],
    "text-shadow": [ test_shadow_transition ],
    "top": [ test_length_transition, test_percent_transition ],
    "vertical-align": [ test_length_transition, test_percent_transition ],
    "width": [ test_length_transition, test_percent_transition ],
    "word-spacing": [ test_length_transition ],
    "z-index": [ test_zindex_transition, test_pos_integer_or_auto_transition ],
};

var div = document.getElementById("display");
var cs = getComputedStyle(div, "");

var prop;
for (prop in supported_properties) {
  // Test that prop is in the property database.
  ok(prop in gCSSProperties, "property " + prop + " in gCSSProperties");

  // Test that the entry has at least one test function.
  ok(supported_properties[prop].length > 0,
     "property " + prop + " must have at least one test function");
}

// Test that transitions don't do anything (i.e., aren't supported) on
// the properties not in our test list above (and not transition
// properties themselves).
for (prop in gCSSProperties) {
  var info = gCSSProperties[prop];
  if (!(prop in supported_properties) &&
      info.type != CSS_TYPE_TRUE_SHORTHAND &&
      !prop.match(/^-moz-transition-/) &&
      // FIXME (Bug 119078): THIS SHOULD REALLY NOT BE NEEDED!
      prop != "-moz-binding") {

    if ("prerequisites" in info) {
      var prereqs = info.prerequisites;
      for (var prereq in prereqs) {
        div.style.setProperty(prereq, prereqs[prereq], "");
      }
    }

    var all_values = info.initial_values.concat(info.other_values);
    var all_computed = [];
    for (var idx in all_values) {
      var val = all_values[idx];
      div.style.setProperty(prop, val, "");
      all_computed.push(cs.getPropertyValue(prop));
    }
    div.style.removeProperty(prop);

    div.style.setProperty("-moz-transition", prop + " 20s linear", "");
    for (var i = 0; i < all_values.length; ++i) {
      for (var j = i + 1; j < all_values.length; ++j) {
        div.style.setProperty(prop, all_values[i], "");
        is(cs.getPropertyValue(prop), all_computed[i],
           "transitions not supported for property " + prop +
           " value " + all_values[i]);
        div.style.setProperty(prop, all_values[j], "");
        is(cs.getPropertyValue(prop), all_computed[j],
           "transitions not supported for property " + prop +
           " value " + all_values[j]);
      }
    }

    div.style.removeProperty(prop);
    div.style.removeProperty("-moz-transition");
    if ("prerequisites" in info) {
      var prereqs = info.prerequisites;
      for (var prereq in prereqs) {
        div.style.removeProperty(prereq);
      }
    }
  }
}

// Do 4-second linear transitions with -2 second transition delay and
// linear timing function so that we can expect the transition to be
// right in the middle just after changing the property.
div.style.setProperty("-moz-transition-duration", "4s", "");
div.style.setProperty("-moz-transition-delay", "-2s", "");
div.style.setProperty("-moz-transition-timing-function", "linear", "");
for (prop in supported_properties) {
  var tinfo = supported_properties[prop];
  var info = gCSSProperties[prop];

  isnot(info.type, CSS_TYPE_TRUE_SHORTHAND,
        prop + " must not be a shorthand");
  if ("prerequisites" in info) {
    var prereqs = info.prerequisites;
    for (var prereq in prereqs) {
      div.style.setProperty(prereq, prereqs[prereq], "");
    }
  }

  for (var idx in tinfo) {
    tinfo[idx](prop);
  }

  // Make sure to unset the property and stop transitions on it.
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty("-moz-transition-delay", "-6s", "");
  div.style.removeProperty(prop);
  cs.getPropertyValue(prop);
  div.style.setProperty("-moz-transition-delay", "-2s", "");

  if ("prerequisites" in info) {
    var prereqs = info.prerequisites;
    for (var prereq in prereqs) {
      div.style.removeProperty(prereq);
    }
  }
}
div.style.removeProperty("-moz-transition");

function test_length_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "4px", "");
  is(cs.getPropertyValue(prop), "4px",
     "length-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "12px", "");
  is(cs.getPropertyValue(prop), "8px",
     "length-valued property " + prop + ": interpolation of lengths");
}

// Test using float values in the range [0, 1] (e.g. opacity)
function test_float_zeroToOne_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "0.3", "");
  is(cs.getPropertyValue(prop), "0.3",
     "float-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "0.8", "");
  is(cs.getPropertyValue(prop), "0.55",
     "float-valued property " + prop + ": interpolation of floats");
}

// Test using float values in the range [1, infinity) (e.g. stroke-miterlimit)
function test_float_aboveOne_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "1", "");
  is(cs.getPropertyValue(prop), "1",
     "float-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "2.1", "");
  is(cs.getPropertyValue(prop), "1.55",
     "float-valued property " + prop + ": interpolation of floats");
}

function test_percent_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "25%", "");
  var av = cs.getPropertyValue(prop);
  var a = any_unit_to_num(av);
  div.style.setProperty(prop, "75%", "");
  var bv = cs.getPropertyValue(prop);
  var b = any_unit_to_num(bv);
  isnot(b, a, "different percentages (" + av + " and " + bv +
              ") should be different for " + prop);
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "25%", "");
  var res = cs.getPropertyValue(prop);
  is(any_unit_to_num(res) * 2, a + b,
     "percent-valued property " + prop + ": interpolation of percents: " +
     res + " should be halfway between " + av + " and " + bv);
  ok(has_num(res),
     "percent-valued property " + prop + ": percent computes to number");
}

function test_color_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "rgb(255, 28, 0)", "");
  is(cs.getPropertyValue(prop), "rgb(255, 28, 0)",
     "color-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "rgb(77, 84, 128)", "");
  is(cs.getPropertyValue(prop), "rgb(166, 56, 64)",
     "color-valued property " + prop + ": interpolation of colors");
}

function test_shadow_transition(prop) {
  var spreadStr = (prop == "-moz-box-shadow") ? " 0px" : "";

  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "none", "");
  is(cs.getPropertyValue(prop), "none",
     "shadow-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "4px 8px 3px red", "");
  is(cs.getPropertyValue(prop), "rgba(255, 0, 0, 0.5) 2px 4px 1.5px" + spreadStr,
     "shadow-valued property " + prop + ": interpolation of shadows");

  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "green 4px 4px, 2px 2px blue", "");
  is(cs.getPropertyValue(prop), "rgb(0, 128, 0) 4px 4px 0px" + spreadStr + ", rgb(0, 0, 255) 2px 2px 0px" + spreadStr,
     "shadow-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "8px 8px 8px red", "");
  is(cs.getPropertyValue(prop), "rgb(128, 64, 0) 6px 6px 4px" + spreadStr + ", rgba(0, 0, 255, 0.5) 1px 1px 0px" + spreadStr,
     "shadow-valued property " + prop + ": interpolation of shadows");

  if (prop == "-moz-box-shadow") {
    div.style.setProperty(prop, "8px 8px 8px red inset", "");
    is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 0px inset",
       "shadow-valued property " + prop + ": non-interpolable cases");
    div.style.setProperty(prop, "8px 8px 8px 8px red inset", "");
    is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 4px inset",
       "shadow-valued property " + prop + ": interpolation of spread");
    // Leave in same state whether in the |if| or not.
    div.style.setProperty(prop, "8px 8px 8px red", "");
    is(cs.getPropertyValue(prop), "rgb(255, 0, 0) 8px 8px 8px 0px",
       "shadow-valued property " + prop + ": non-interpolable cases");
  }

  var defaultColor = cs.getPropertyValue("color") + " ";
  div.style.setProperty(prop, "2px 2px 2px", "");
  is(cs.getPropertyValue(prop), defaultColor + "2px 2px 2px" + spreadStr,
     "shadow-valued property " + prop + ": non-interpolable cases");
  div.style.setProperty(prop, "4px 8px 6px", "");
  is(cs.getPropertyValue(prop), defaultColor + "3px 5px 4px" + spreadStr,
     "shadow-valued property " + prop + ": interpolation without color");
}

function test_dasharray_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "3", "");
  is(cs.getPropertyValue(prop), "3",
     "dasharray-valued property " + prop +
     ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "9px", "");
  is(cs.getPropertyValue(prop), "6",
     "dasharray-valued property " + prop + ": interpolation of dasharray");
  div.style.setProperty(prop, "none", "");
  is(cs.getPropertyValue(prop), "none",
     "dasharray-valued property " + prop + ": non-interpolability of none");
  div.style.setProperty(prop, "6,8px,4,4", "");
  is(cs.getPropertyValue(prop), "6, 8px, 4, 4",
     "dasharray-valued property " + prop +
     ": computed value before transition");
  div.style.setProperty(prop, "10, 10,10,10px", "");
  is(cs.getPropertyValue(prop), "8, 9, 7, 7",
     "dasharray-valued property " + prop + ": interpolation of dasharray");
  div.style.setProperty(prop, "none", "");
  is(cs.getPropertyValue(prop), "none",
     "dasharray-valued property " + prop + ": non-interpolability of none");
  div.style.setProperty(prop, "4,8,2", "");
  is(cs.getPropertyValue(prop), "4, 8, 2",
     "dasharray-valued property " + prop +
     ": computed value before transition");
  div.style.setProperty(prop, "2,4,6,8", "");
  is(cs.getPropertyValue(prop), "3, 6, 4, 6, 5, 3, 5, 8, 2, 4, 7, 5",
     "dasharray-valued property " + prop + ": interpolation of dasharray");
  div.style.setProperty(prop, "2,50%,6,8", "");
  is(cs.getPropertyValue(prop), "2, 50%, 6, 8",
     "dasharray-valued property " + prop + ": non-interpolability of mixed units");
  div.style.setProperty(prop, "4,20%,2,2", "");
  is(cs.getPropertyValue(prop), "3, 35%, 4, 5",
     "dasharray-valued property " + prop + ": interpolation of dasharray");
}

function test_radius_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");

  // FIXME: Test a square for now, since we haven't updated to the spec
  // for vertical components being relative to the height.
  div.style.setProperty("width", "200px", "");
  div.style.setProperty("height", "200px", "");
  div.style.setProperty("border", "none", "");
  div.style.setProperty("padding", "0", "");

  div.style.setProperty(prop, "3px", "");
  is(cs.getPropertyValue(prop), "3px",
     "radius-valued property " + prop +
     ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "9px", "");
  is(cs.getPropertyValue(prop), "6px",
     "radius-valued property " + prop + ": interpolation of radius");
  div.style.setProperty(prop, "5%", "");
  is(cs.getPropertyValue(prop), "10px",
     "radius-valued property " + prop + ": non-interpolability of unit change");
  div.style.setProperty(prop, "25%", "");
  is(cs.getPropertyValue(prop), "30px",
     "radius-valued property " + prop + ": interpolation of radius");
  div.style.setProperty(prop, "3px 8px", "");
  is(cs.getPropertyValue(prop), "3px 8px",
     "radius-valued property " + prop + ": non-interpolability of unit change");
  div.style.setProperty(prop, "9px 10px", "");
  is(cs.getPropertyValue(prop), "6px 9px",
     "radius-valued property " + prop + ": interpolation of radius");
  div.style.setProperty(prop, "5% 15%", "");
  is(cs.getPropertyValue(prop), "10px 30px",
     "radius-valued property " + prop + ": non-interpolability of unit change");
  div.style.setProperty(prop, "25%", "");
  is(cs.getPropertyValue(prop), "30px 40px",
     "radius-valued property " + prop + ": interpolation of radius");

  div.style.removeProperty("width");
  div.style.removeProperty("height");
  div.style.removeProperty("border");
  div.style.removeProperty("padding");
}

function test_zindex_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "4", "");
  is(cs.getPropertyValue(prop), "4",
     "integer-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "-5", "");
  is(cs.getPropertyValue(prop), "-1",
     "integer-valued property " + prop + ": interpolation of lengths");
  div.style.setProperty(prop, "auto", "");
  is(cs.getPropertyValue(prop), "auto",
     "integer-valued property " + prop + ": auto not interpolable");
  div.style.setProperty(prop, "-4", "");
  is(cs.getPropertyValue(prop), "-4",
     "integer-valued property " + prop + ": computed value before transition");
  div.style.setProperty(prop, "8", "");
  is(cs.getPropertyValue(prop), "2",
     "integer-valued property " + prop + ": interpolation of lengths");
}

function test_font_stretch(prop) {
  is(prop, "font-stretch", "only designed for one property");

  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "normal", "");
  is(cs.getPropertyValue(prop), "normal",
     "font-stretch property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "ultra-expanded", "");
  is(cs.getPropertyValue(prop), "expanded",
     "font-stretch property " + prop + ": interpolation of font-stretches");
  div.style.setProperty(prop, "wider", "");
  is(cs.getPropertyValue(prop), "wider",
     "font-stretch property " + prop + ": can't interpolate wider/narrower");
  div.style.setProperty(prop, "expanded", "");
  is(cs.getPropertyValue(prop), "expanded",
     "font-stretch property " + prop + ": computed value before transition");
  div.style.setProperty(prop, "extra-condensed", "");
  is(cs.getPropertyValue(prop), "semi-condensed",
     "font-stretch property " + prop + ": interpolation of font-stretches");
}

function test_font_weight(prop) {
  is(prop, "font-weight", "only designed for one property");

  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "normal", "");
  is(cs.getPropertyValue(prop), "400",
     "font-weight property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "900", "");
  is(cs.getPropertyValue(prop), "600",
     "font-weight property " + prop + ": interpolation of font-weights");
  div.style.setProperty(prop, "lighter", "");
  is(cs.getPropertyValue(prop), "lighter",
     "font-weight property " + prop + ": can't interpolate bolder/lighter");
  div.style.setProperty(prop, "700", "");
  is(cs.getPropertyValue(prop), "700",
     "font-weight property " + prop + ": computed value before transition");
  div.style.setProperty(prop, "100", "");
  is(cs.getPropertyValue(prop), "400",
     "font-weight property " + prop + ": interpolation of font-weights");
}

function test_pos_integer_or_auto_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "4", "");
  is(cs.getPropertyValue(prop), "4",
     "integer-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "7", "");
  is(cs.getPropertyValue(prop), "5",
     "integer-valued property " + prop + ": interpolation of lengths");
  div.style.setProperty(prop, "auto", "");
  is(cs.getPropertyValue(prop), "auto",
     "integer-valued property " + prop + ": auto not interpolable");
  div.style.setProperty(prop, "8", "");
  is(cs.getPropertyValue(prop), "8",
     "integer-valued property " + prop + ": computed value before transition");
  div.style.setProperty(prop, "4", "");
  is(cs.getPropertyValue(prop), "6",
     "integer-valued property " + prop + ": interpolation of lengths");
}

function test_length_pair_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "4px 8px", "");
  is(cs.getPropertyValue(prop), "4px 8px",
     "length-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "12px 10px", "");
  is(cs.getPropertyValue(prop), "8px 9px",
     "length-valued property " + prop + ": interpolation of lengths");
}

function test_length_percent_pair_transition(prop) {
  div.style.setProperty("-moz-transition-property", "none", "");
  div.style.setProperty(prop, "4px 50%", "");
  is(cs.getPropertyValue(prop), "4px 50%",
     "length-valued property " + prop + ": computed value before transition");
  div.style.setProperty("-moz-transition-property", prop, "");
  div.style.setProperty(prop, "12px 70%", "");
  is(cs.getPropertyValue(prop), "8px 60%",
     "length-valued property " + prop + ": interpolation of lengths");
}

</script>
</pre>
</body>
</html>