DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (b6057e17f856)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
<!DOCTYPE HTML>
<html>
<!--
-->
<head>
  <title>Test for parsing, storage, and serialization of CSS values</title>
  <script type="text/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" id="prereqsheet">
  #testnode {}
  </style>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">

<div id="testnode"></div>

</div>
<pre id="test">
<script class="testbody" type="text/javascript">

/** Test for parsing, storage, and serialization of CSS values **/

/*
 * The idempotence tests here deserve a little bit of explanation.  What
 * we're testing here are the following operations:
 *   parse: string -> CSS rule
 *   serialize: CSS rule -> string (normalization 1)
 *     (this actually has two variants that go through partly different
 *     codepaths, which we exercise with getPropertyValue and cssText)
 *   compute: CSS rule -> computed style
 *   cserialize: computed style -> string (normalization 2)
 *
 * Both serialize and cserialize do some normalization, so we can't test
 * for pure round-tripping, and we also can't compare their output since
 * they could normalize differently.  (We might at some point in the
 * future want to guarantee that any output of cserialize is
 * untouched by going through parse+serialize, though.)
 *
 * So we test idempotence of parse + serialize by running the whole
 * operation twice.  Likewise for parse + compute + cserialize.
 *
 * Slightly more interestingly, we test that serialize + parse is the
 * identity transform by comparing the output of parse + compute +
 * cserialize to the output of parse + serialize + parse + compute +
 * cserialize.
 */

var gSystemFont = {
  "caption": true,
  "icon": true,
  "menu": true,
  "message-box": true,
  "small-caption": true,
  "status-bar": true,
  "-moz-window": true,
  "-moz-document": true,
  "-moz-desktop": true,
  "-moz-info": true,
  "-moz-dialog": true,
  "-moz-button": true,
  "-moz-pull-down-menu": true,
  "-moz-list": true,
  "-moz-field": true,
  "-moz-workspace": true,
};

var gBadCompute = {
  // output wrapped around to positive, in exponential notation
  "-moz-box-ordinal-group": [ "-1", "-1000" ],
};

function xfail_compute(property, value)
{
  if (property in gBadCompute &&
      gBadCompute[property].indexOf(value) != -1)
    return true;

  return false;
}

var gElement = document.getElementById("testnode");
var gDeclaration = gElement.style;
var gComputedStyle = window.getComputedStyle(gElement, "");

var gPrereqDeclaration =
  document.getElementById("prereqsheet").sheet.cssRules[0].style;

function test_property(property)
{
  ok(SpecialPowers.getBoolPref("layout.css.variables.enabled"), "pref not set #2");
  var info = gCSSProperties[property];

  var test_computed = !("backend_only" in info);

  // can all properties be removed from the style?
  function test_remove_all_properties(property, value) {
    var i, p = [];
    for (i = 0; i < gDeclaration.length; i++) p.push(gDeclaration[i]);
    for (i = 0; i < p.length; i++) gDeclaration.removeProperty(p[i]);
    var errstr = "when setting property " + property + " to " + value;
    is(gDeclaration.length, 0, "unremovable properties " + errstr);
    is(gDeclaration.cssText, "", "non-empty serialization after removing all properties " + errstr);
  }

  function test_value(value, resolved_value) {
    var value_has_variable_reference = resolved_value != null;

    gDeclaration.setProperty(property, value, "");

    var idx;

    var step1val = gDeclaration.getPropertyValue(property);
    var step1vals = [];
    var step1ser = gDeclaration.cssText;
    if ("subproperties" in info)
      for (idx in info.subproperties)
        step1vals.push(gDeclaration.getPropertyValue(info.subproperties[idx]));
    var step1comp;
    var step1comps = [];
    if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND)
      step1comp = gComputedStyle.getPropertyValue(property);
    if (test_computed && "subproperties" in info)
      for (idx in info.subproperties)
        step1comps.push(gComputedStyle.getPropertyValue(info.subproperties[idx]));

    isnot(step1val, "", "setting '" + value + "' on '" + property + "'");
    if ("subproperties" in info)
      for (idx in info.subproperties) {
        var subprop = info.subproperties[idx];
        if (value_has_variable_reference &&
            (!info.alias_for || info.type == CSS_TYPE_TRUE_SHORTHAND)) {
          is(gDeclaration.getPropertyValue(subprop), "",
             "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
        } else {
          isnot(gDeclaration.getPropertyValue(subprop), "",
                "setting '" + value + "' on '" + property + "' (for '" + subprop + "')");
        }
      }

    // We don't care particularly about the whitespace or the placement of
    // semicolons, but for simplicity we'll test the current behavior.
    var expected_serialization = "";
    if (step1val != "") {
      if ("alias_for" in info) {
        expected_serialization = info.alias_for + ": " + step1val + ";";
      } else {
        expected_serialization = property + ": " + step1val + ";";
      }
    }
    is(step1ser, expected_serialization,
       "serialization should match property value");

    gDeclaration.removeProperty(property);
    gDeclaration.setProperty(property, step1val, "");

    is(gDeclaration.getPropertyValue(property), step1val,
       "parse+serialize should be idempotent for '" +
         property + ": " + value + "'");
    if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
      is(gComputedStyle.getPropertyValue(property), step1comp,
         "serialize+parse should be identity transform for '" +
         property + ": " + value + "'");
    }

    if ("subproperties" in info &&
        // Using setProperty over subproperties is not sufficient for
        // system fonts, since the shorthand does more than its parts.
        (property != "font" || !(value in gSystemFont)) &&
        // Likewise for special compatibility values of transform
        (property != "-moz-transform" || !value.match(/^matrix.*(px|em|%)/)) &&
        !value_has_variable_reference) {
      gDeclaration.removeProperty(property);
      for (idx in info.subproperties) {
        var subprop = info.subproperties[idx];
        gDeclaration.setProperty(subprop, step1vals[idx], "");
      }

      // Now that all the subprops are set, check their values.  Note that we
      // need this in a separate loop, in case parts of the shorthand affect
      // the computed values of other parts.
      for (idx in info.subproperties) {
        var subprop = info.subproperties[idx];
        if (test_computed && !("backend_only" in gCSSProperties[subprop])) {
          is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
             "serialize(" + subprop + ")+parse should be the identity " +
             "transform for '" + property + ": " + value + "'");
        }
      }
      is(gDeclaration.getPropertyValue(property), step1val,
         "parse+split+serialize should be idempotent for '" +
         property + ": " + value + "'");
    }

    if (test_computed && info.type != CSS_TYPE_TRUE_SHORTHAND) {
      gDeclaration.removeProperty(property);
      gDeclaration.setProperty(property, step1comp, "");
      var func = xfail_compute(property, value) ? todo_is : is;
      func(gComputedStyle.getPropertyValue(property), step1comp,
           "parse+compute+serialize should be idempotent for '" +
           property + ": " + value + "'");
    }
    if (test_computed && "subproperties" in info) {
      gDeclaration.removeProperty(property);
      for (idx in info.subproperties) {
        var subprop = info.subproperties[idx];
        if ("backend_only" in gCSSProperties[subprop])
          continue;
        gDeclaration.setProperty(subprop, step1comps[idx], "");
      }

      // Now that all the subprops are set, check their values.  Note that we
      // need this in a separate loop, in case parts of the shorthand affect
      // the computed values of other parts.
      for (idx in info.subproperties) {
        var subprop = info.subproperties[idx];
        if ("backend_only" in gCSSProperties[subprop])
          continue;
        is(gComputedStyle.getPropertyValue(subprop), step1comps[idx],
           "parse+compute+serialize(" + subprop + ") should be idempotent for '" +
           property + ": " + value + "'");
      }
    }

    // sanity check shorthands to make sure disabled props aren't exposed
    if (info.type != CSS_TYPE_LONGHAND) {
      gDeclaration.setProperty(property, value, "");
      test_remove_all_properties(property, value);
    }

    gDeclaration.removeProperty(property);
  }

  function test_value_without_variable(value) {
    test_value(value, null);
  }

  function test_value_with_variable(value) {
    gPrereqDeclaration.setProperty("--a", value, "");
    test_value("var(--a)", value);
    gPrereqDeclaration.removeProperty("--a");
  }

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

  var idx;
  for (idx in info.initial_values) {
    test_value_without_variable(info.initial_values[idx]);
    test_value_with_variable(info.initial_values[idx]);
  }
  for (idx in info.other_values) {
    test_value_without_variable(info.other_values[idx]);
    test_value_with_variable(info.other_values[idx]);
  }

  if ("prerequisites" in info) {
    for (var prereq in info.prerequisites) {
      gPrereqDeclaration.removeProperty(prereq);
    }
  }

}

function runTest() {
  // To avoid triggering the slow script dialog, we have to test one
  // property at a time.
  ok(SpecialPowers.getBoolPref("layout.css.variables.enabled"), "pref not set #1");
  var props = [];
  for (var prop in gCSSProperties)
    props.push(prop);
  props = props.reverse();
  function do_one() {
    if (props.length == 0) {
      SimpleTest.finish();
      return;
    }
    test_property(props.pop());
    SimpleTest.executeSoon(do_one);
  }
  SimpleTest.executeSoon(do_one);
}

SimpleTest.waitForExplicitFinish();
SimpleTest.requestLongerTimeout(2);

SpecialPowers.pushPrefEnv({ set: [["layout.css.variables.enabled", true]] },
                          runTest);
</script>
</pre>
</body>
</html>