tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_media_queries.html (36564B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 https://bugzilla.mozilla.org/show_bug.cgi?id=156716
      5 -->
      6 <head>
      7  <title>Test for Bug 156716</title>
      8  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      9  <script src="chrome/chrome-only-media-queries.js"></script>
     10  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     11 </head>
     12 <body onload="run()">
     13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=156716">Mozilla Bug 156716</a>
     14 <iframe id="subdoc" src="media_queries_iframe.html"></iframe>
     15 <div id="content" style="display: none">
     16 
     17 </div>
     18 <pre id="test">
     19 <script class="testbody" type="application/javascript">
     20 
     21 /** Test for Bug 156716 */
     22 
     23 // Note that many other tests are in test_acid3_test46.html .
     24 
     25 SimpleTest.waitForExplicitFinish();
     26 SimpleTest.requestLongerTimeout(2);
     27 
     28 var iframe;
     29 
     30 function getScreenPixelsPerCSSPixel() {
     31  return window.devicePixelRatio;
     32 }
     33 
     34 function run() {
     35  iframe = document.getElementById("subdoc");
     36  var subdoc = iframe.contentDocument;
     37  var subwin = iframe.contentWindow;
     38  var style = subdoc.getElementById("style");
     39  var iframe_style = iframe.style;
     40  var body_cs = subdoc.defaultView.getComputedStyle(subdoc.body);
     41 
     42  function query_applies(q) {
     43    style.setAttribute("media", q);
     44    return body_cs.getPropertyValue("text-decoration-line") == "underline";
     45  }
     46 
     47  function should_apply(q) {
     48    ok(query_applies(q), q + " should apply");
     49    test_serialization(q, true, true);
     50  }
     51 
     52  function should_not_apply(q) {
     53    ok(!query_applies(q), q + " should not apply");
     54    test_serialization(q, true, false);
     55  }
     56 
     57  /* for queries that are parseable standalone but not within CSS */
     58  function should_apply_unbalanced(q) {
     59    ok(query_applies(q), q + " should apply");
     60  }
     61 
     62  /* for queries that are parseable standalone but not within CSS */
     63  function should_not_apply_unbalanced(q) {
     64    ok(!query_applies(q), q + " should not apply");
     65  }
     66 
     67  /*
     68   * Functions to test whether a query is parseable at all.  (Should not
     69   * be used for parse errors within expressions.)
     70   */
     71  var parse_test_style_element = document.createElement("style");
     72  parse_test_style_element.type = "text/css";
     73  parse_test_style_element.disabled = true; // for performance, hopefully
     74  var parse_test_style_text = document.createTextNode("");
     75  parse_test_style_element.appendChild(parse_test_style_text);
     76  document.getElementsByTagName("head")[0]
     77    .appendChild(parse_test_style_element);
     78 
     79  function query_is_parseable(q) {
     80    parse_test_style_text.data = "@media screen, " + q + " {}";
     81    var sheet = parse_test_style_element.sheet; // XXX yikes, not live!
     82    if (sheet.cssRules.length == 1 &&
     83        sheet.cssRules[0].type == CSSRule.MEDIA_RULE)
     84      return sheet.cssRules[0].media.mediaText != "screen, not all";
     85    ok(false, "unexpected result testing whether query " + q +
     86              " is parseable");
     87    return true; // doesn't matter, we already failed
     88  }
     89 
     90  function query_should_be_parseable(q) {
     91    ok(query_is_parseable(q), "query " + q + " should be parseable");
     92    test_serialization(q, false, false);
     93  }
     94 
     95  function query_should_not_be_parseable(q) {
     96    ok(!query_is_parseable(q), "query " + q + " should not be parseable");
     97  }
     98 
     99  function expression_should_be_known(e) {
    100    should_apply(`(${e}) or (not (${e}))`);
    101  }
    102 
    103  function expression_should_not_be_known(e) {
    104    should_not_apply(`(${e}) or (not (${e}))`);
    105  }
    106 
    107  // Helper to share code between -moz & -webkit device-pixel-ratio versions:
    108  function test_device_pixel_ratio(equal_name, min_name, max_name) {
    109    var real_dpr = 1.0 * getScreenPixelsPerCSSPixel();
    110    var high_dpr = 1.1 * getScreenPixelsPerCSSPixel();
    111    var low_dpr = 0.9 * getScreenPixelsPerCSSPixel();
    112    should_apply("all and (" + max_name + ": " + real_dpr + ")");
    113    should_apply("all and (" + min_name + ": " + real_dpr + ")");
    114    should_not_apply("not all and (" + max_name + ": " + real_dpr + ")");
    115    should_not_apply("not all and (" + min_name + ": " + real_dpr + ")");
    116    should_apply("all and (" + min_name + ": " + low_dpr + ")");
    117    should_apply("all and (" + max_name + ": " + high_dpr + ")");
    118    should_not_apply("all and (" + max_name + ": " + low_dpr + ")");
    119    should_not_apply("all and (" + min_name + ": " + high_dpr + ")");
    120    should_apply("not all and (" + max_name + ": " + low_dpr + ")");
    121    should_apply("not all and (" + min_name + ": " + high_dpr + ")");
    122    should_apply("(" + equal_name + ": " + real_dpr + ")");
    123    should_not_apply("(" + equal_name + ": " + high_dpr + ")");
    124    should_not_apply("(" + equal_name + ": " + low_dpr + ")");
    125    should_apply("(" + equal_name + ")");
    126    expression_should_not_be_known(min_name);
    127    expression_should_not_be_known(max_name);
    128  }
    129 
    130  function test_serialization(q, test_application, expected_to_apply) {
    131    style.setAttribute("media", q);
    132    var ser1 = style.sheet.media.mediaText;
    133    isnot(ser1, "", "serialization of '" + q + "' should not be empty");
    134    style.setAttribute("media", ser1);
    135    var ser2 = style.sheet.media.mediaText;
    136    is(ser2, ser1, "parse+serialize of '" + q + "' should be idempotent");
    137    if (test_application) {
    138      let applies = body_cs.getPropertyValue("text-decoration-line") ==
    139                    "underline";
    140      is(applies, expected_to_apply,
    141         "Media query '" + q + "' should " + (expected_to_apply ? "" : "NOT ") +
    142         "apply after serialize + reparse");
    143    }
    144 
    145    // Test cloning
    146    var sheet = "@media " + q + " { body { text-decoration: underline } }"
    147    var sheeturl = "data:text/css," + escape(sheet);
    148    var link = "<link rel='stylesheet' href='" + sheeturl + "'>";
    149    var htmldoc = "<!DOCTYPE HTML>" + link + link  + "<body>";
    150    post_clone_test(htmldoc, function() {
    151      var clonedoc = iframe.contentDocument;
    152      var clonewin = iframe.contentWindow;
    153      var links = clonedoc.getElementsByTagName("link");
    154      // cause a clone
    155      var clonedsheet = links[1].sheet;
    156      clonedsheet.insertRule("#nonexistent { color: purple}", 1);
    157      // remove the uncloned sheet
    158      links[0].remove();
    159 
    160      var ser3 = clonedsheet.cssRules[0].media.mediaText;
    161      is(ser3, ser1, "cloning query '" + q + "' should not change " +
    162                     "serialization");
    163      if (test_application) {
    164        let applies = clonewin.getComputedStyle(clonedoc.body).
    165                        textDecorationLine == "underline";
    166        is(applies, expected_to_apply,
    167           "Media query '" + q + "' should " + (expected_to_apply ? "" : "NOT ") +
    168           "apply after cloning");
    169      }
    170    });
    171  }
    172 
    173  // The no-type syntax doesn't mix with the not and only keywords.
    174  expression_should_be_known("(orientation)");
    175  expression_should_be_known("not (orientation)");
    176  query_should_not_be_parseable("only (orientation)");
    177  query_should_be_parseable("all and (orientation)");
    178  query_should_be_parseable("not all and (orientation)");
    179  query_should_be_parseable("only all and (orientation)");
    180 
    181  query_should_not_be_parseable("not not (orientation)");
    182  expression_should_be_known("(orientation) and (orientation)");
    183  expression_should_be_known("(orientation) or (orientation)");
    184  expression_should_be_known("(orientation) or ((orientation) and ((orientation) or (orientation) or (not (orientation))))");
    185 
    186  query_should_not_be_parseable("all and (orientation) or (orientation)");
    187  query_should_be_parseable("all and (orientation) and (orientation)");
    188 
    189  query_should_not_be_parseable("(orientation) and (orientation) or (orientation)");
    190  query_should_not_be_parseable("(orientation) and not (orientation)");
    191 
    192  query_should_be_parseable("(-moz-device-orientation)");
    193  query_should_be_parseable("not (-moz-device-orientation)");
    194  query_should_not_be_parseable("only (-moz-device-orientation)");
    195  query_should_be_parseable("all and (-moz-device-orientation)");
    196  query_should_be_parseable("not all and (-moz-device-orientation)");
    197  query_should_be_parseable("only all and (-moz-device-orientation)");
    198 
    199  // Test that the 'not', 'only', 'and', and 'or' keywords are not
    200  // allowed as media types.
    201  query_should_not_be_parseable("not");
    202  query_should_not_be_parseable("and");
    203  query_should_not_be_parseable("or");
    204  query_should_not_be_parseable("only");
    205  query_should_be_parseable("unknowntype");
    206  query_should_not_be_parseable("not not");
    207  query_should_not_be_parseable("not and");
    208  query_should_not_be_parseable("not or");
    209  query_should_not_be_parseable("not only");
    210  query_should_be_parseable("not unknowntype");
    211  query_should_not_be_parseable("only not");
    212  query_should_not_be_parseable("only and");
    213  query_should_not_be_parseable("only or");
    214  query_should_not_be_parseable("only only");
    215  query_should_be_parseable("only unknowntype");
    216  query_should_not_be_parseable("not and (width)");
    217  query_should_not_be_parseable("and and (width)");
    218  query_should_not_be_parseable("or and (width)");
    219  query_should_not_be_parseable("only and (width)");
    220  query_should_be_parseable("unknowntype and (width)");
    221  query_should_not_be_parseable("not not and (width)");
    222  query_should_not_be_parseable("not and and (width)");
    223  query_should_not_be_parseable("not or and (width)");
    224  query_should_not_be_parseable("not only and (width)");
    225  query_should_be_parseable("not unknowntype and (width)");
    226  query_should_not_be_parseable("only not and (width)");
    227  query_should_not_be_parseable("only and and (width)");
    228  query_should_not_be_parseable("only or and (width)");
    229  query_should_not_be_parseable("only only and (width)");
    230  query_should_be_parseable("only unknowntype and (width)");
    231 
    232  var features = [ "width", "height", "device-width", "device-height" ];
    233  var separators = [ ":", ">", ">=", "=", "<=", "<" ];
    234 
    235  var feature;
    236  var i;
    237  for (i in features) {
    238    feature = features[i];
    239    expression_should_be_known(feature);
    240    expression_should_not_be_known("min-" + feature);
    241    expression_should_not_be_known("max-" + feature);
    242    for (let separator of separators) {
    243      expression_should_be_known(feature + " " + separator + " 0");
    244      expression_should_be_known(feature + " " + separator + " 0px");
    245      expression_should_be_known(feature + " " + separator + " 0em");
    246      expression_should_be_known(feature + " " + separator + " -0");
    247      expression_should_be_known(feature + " " + separator + " -0cm");
    248      expression_should_be_known(feature + " " + separator + " 1px");
    249      expression_should_be_known(feature + " " + separator + " 0.001mm");
    250      expression_should_be_known(feature + " " + separator + " 100000px");
    251      expression_should_be_known(feature + " " + separator + " -1px");
    252      if (separator == ":") {
    253        expression_should_be_known("min-" + feature + " " + separator + " -0");
    254        expression_should_be_known("max-" + feature + " " + separator + " -0");
    255        expression_should_be_known("min-" + feature + " " + separator + " -1px");
    256        expression_should_be_known("max-" + feature + " " + separator + " -1px");
    257        expression_should_be_known(feature + " " + separator + " -0.00001mm");
    258        expression_should_be_known(feature + " " + separator + " -100000em");
    259      } else {
    260        expression_should_not_be_known("min-" + feature + " " + separator + " -0");
    261        expression_should_not_be_known("max-" + feature + " " + separator + " -0");
    262        expression_should_not_be_known("min-" + feature + " " + separator + " -1px");
    263        expression_should_not_be_known("max-" + feature + " " + separator + " -1px");
    264        let multi_range = "0px " + separator + " " + feature + " " + separator + " 100000px"
    265        if (separator == "=") {
    266          expression_should_not_be_known(multi_range);
    267        } else {
    268          expression_should_be_known(multi_range);
    269        }
    270      }
    271      if (separator == ">=") {
    272        expression_should_not_be_known(feature + " > = 0px");
    273      } else if (separator == "<=") {
    274        expression_should_not_be_known(feature + " < = 0px");
    275      }
    276    }
    277  }
    278 
    279  var mediatypes = ["browser", "minimal-ui", "standalone", "fullscreen"];
    280 
    281  mediatypes.forEach(function(type) {
    282    expression_should_be_known("display-mode: " + type);
    283  });
    284 
    285  if (SpecialPowers.getBoolPref("dom.documentpip.enabled")) {
    286    expression_should_be_known("display-mode: picture-in-picture");
    287  } else {
    288    expression_should_not_be_known("display-mode: picture-in-picture");
    289  }
    290 
    291  expression_should_not_be_known("display-mode: invalid")
    292 
    293  var content_div = document.getElementById("content");
    294  content_div.style.font = "initial";
    295  var em_size =
    296    getComputedStyle(content_div, "").fontSize.match(/^(\d+)px$/)[1];
    297 
    298  // in this test, assume the common underlying implementation is correct
    299  var width_val = 117; // pick two not-too-round numbers
    300  var height_val = 76;
    301  change_state(function() {
    302    iframe_style.width = width_val + "px";
    303    iframe_style.height = height_val + "px";
    304  });
    305  var device_width = window.screen.width;
    306  var device_height = window.screen.height;
    307  features = {
    308    "width": width_val,
    309    "height": height_val,
    310    "device-width": device_width,
    311    "device-height": device_height
    312  };
    313  for (feature in features) {
    314    var value = features[feature];
    315    should_apply("all and (" + feature + ": " + value + "px)");
    316    should_apply("all and (" + feature + " = " + value + "px)");
    317    should_not_apply("all and (" + feature + ": " + (value + 1) + "px)");
    318    should_not_apply("all and (" + feature + ": " + (value - 1) + "px)");
    319    should_not_apply("all and (" + feature + " = " + (value + 1) + "px)");
    320    should_not_apply("all and (" + feature + " = " + (value - 1) + "px)");
    321 
    322    should_apply("all and (min-" + feature + ": " + value + "px)");
    323    should_not_apply("all and (min-" + feature + ": " + (value + 1) + "px)");
    324    should_apply("all and (min-" + feature + ": " + (value - 1) + "px)");
    325    should_apply("all and (max-" + feature + ": " + value + "px)");
    326    should_apply("all and (max-" + feature + ": " + (value + 1) + "px)");
    327    should_not_apply("all and (max-" + feature + ": " + (value - 1) + "px)");
    328    should_not_apply("all and (min-" + feature + ": " +
    329                     (Math.ceil(value/em_size) + 1) + "em)");
    330    should_apply("all and (min-" + feature + ": " +
    331                 (Math.floor(value/em_size) - 1) + "em)");
    332    should_apply("all and (max-" + feature + ": " +
    333                 (Math.ceil(value/em_size) + 1) + "em)");
    334    should_not_apply("all and (max-" + feature + ": " +
    335                     (Math.floor(value/em_size) - 1) + "em)");
    336    should_not_apply("all and (min-" + feature + ": " +
    337                     (Math.ceil(value/em_size) + 1) + "rem)");
    338    should_apply("all and (min-" + feature + ": " +
    339                 (Math.floor(value/em_size) - 1) + "rem)");
    340    should_apply("all and (max-" + feature + ": " +
    341                 (Math.ceil(value/em_size) + 1) + "rem)");
    342    should_not_apply("all and (max-" + feature + ": " +
    343                     (Math.floor(value/em_size) - 1) + "rem)");
    344 
    345    should_apply("(" + feature + " <= " + value + "px)");
    346    should_apply("(" + feature + " >= " + value + "px)");
    347 
    348    should_apply("(0px < " + feature + " <= " + value + "px)");
    349    should_apply("(" + value + "px >= " + feature + " > 0px)");
    350 
    351    should_not_apply("(0px < " + feature + " < " + value + "px)");
    352    should_not_apply("(" + value + "px > " + feature + " > 0px)");
    353 
    354    should_not_apply("(" + feature + " < " + value + "px)");
    355    should_not_apply("(" + feature + " > " + value + "px)");
    356 
    357    should_apply("(" + feature + " < " + (value + 1) + "px)");
    358    should_apply("(" + feature + " <= " + (value + 1) + "px)");
    359    should_not_apply("(" + feature + " > " + (value + 1) + "px)");
    360    should_not_apply("(" + feature + " >= " + (value + 1) + "px)");
    361 
    362    should_apply("(" + feature + " > " + (value - 1) + "px)");
    363    should_apply("(" + feature + " >= " + (value - 1) + "px)");
    364    should_not_apply("(" + feature + " < " + (value - 1) + "px)");
    365    should_not_apply("(" + feature + " <= " + (value - 1) + "px)");
    366  }
    367 
    368  change_state(function() {
    369    iframe_style.width = "0";
    370  });
    371  should_apply("all and (height)");
    372  should_not_apply("all and (width)");
    373  change_state(function() {
    374    iframe_style.height = "0";
    375  });
    376  should_not_apply("all and (height)");
    377  should_not_apply("all and (width)");
    378  should_apply("all and (device-height)");
    379  should_apply("all and (device-width)");
    380  change_state(function() {
    381    iframe_style.width = width_val + "px";
    382  });
    383  should_not_apply("all and (height)");
    384  should_apply("all and (width)");
    385  change_state(function() {
    386    iframe_style.height = height_val + "px";
    387  });
    388  should_apply("all and (height)");
    389  should_apply("all and (width)");
    390 
    391  // ratio that reduces to 59/40
    392  change_state(function() {
    393    iframe_style.width = "236px";
    394    iframe_style.height = "160px";
    395  });
    396  expression_should_be_known("orientation");
    397  expression_should_be_known("orientation: portrait");
    398  expression_should_be_known("orientation: landscape");
    399  expression_should_not_be_known("min-orientation");
    400  expression_should_not_be_known("min-orientation: portrait");
    401  expression_should_not_be_known("min-orientation: landscape");
    402  expression_should_not_be_known("max-orientation");
    403  expression_should_not_be_known("max-orientation: portrait");
    404  expression_should_not_be_known("max-orientation: landscape");
    405  should_apply("(orientation)");
    406  should_apply("(orientation: landscape)");
    407  should_not_apply("(orientation: portrait)");
    408  should_apply("not all and (orientation: portrait)");
    409  // ratio that reduces to 59/80
    410  change_state(function() {
    411    iframe_style.height = "320px";
    412  });
    413  should_apply("(orientation)");
    414  should_not_apply("(orientation: landscape)");
    415  should_apply("not all and (orientation: landscape)");
    416  should_apply("(orientation: portrait)");
    417 
    418  expression_should_be_known("-moz-device-orientation");
    419  expression_should_be_known("-moz-device-orientation: portrait");
    420  expression_should_be_known("-moz-device-orientation: landscape");
    421  expression_should_not_be_known("min--moz-device-orientation");
    422  expression_should_not_be_known("min--moz-device-orientation: portrait");
    423  expression_should_not_be_known("min--moz-device-orientation: landscape");
    424  expression_should_not_be_known("max--moz-device-orientation");
    425  expression_should_not_be_known("max--moz-device-orientation: portrait");
    426  expression_should_not_be_known("max--moz-device-orientation: landscape");
    427 
    428  // determine the actual configuration of the screen and test against it
    429  var device_orientation = (device_width > device_height) ? "landscape" : "portrait";
    430  var not_device_orientation = (device_orientation == "landscape") ? "portrait" : "landscape";
    431  should_apply("(-moz-device-orientation)");
    432  should_apply("(-moz-device-orientation: " + device_orientation + ")");
    433  should_not_apply("(-moz-device-orientation: " + not_device_orientation + ")");
    434  should_apply("not all and (-moz-device-orientation: " + not_device_orientation + ")");
    435 
    436  should_apply("(aspect-ratio: 59/80)");
    437  should_not_apply("(aspect-ratio: 58/80)");
    438  should_not_apply("(aspect-ratio: 59/81)");
    439  should_not_apply("(aspect-ratio: 60/80)");
    440  should_not_apply("(aspect-ratio: 59/79)");
    441  should_apply("(aspect-ratio: 177/240)");
    442  should_apply("(aspect-ratio: 413/560)");
    443  should_apply("(aspect-ratio: 5900/8000)");
    444  should_not_apply("(aspect-ratio: 5901/8000)");
    445  should_not_apply("(aspect-ratio: 5899/8000)");
    446  should_not_apply("(aspect-ratio: 5900/8001)");
    447  should_not_apply("(aspect-ratio: 5900/7999)");
    448  should_apply("(aspect-ratio)");
    449 
    450  // Test "unreasonable", but still valid aspect ratios, such as aspect ratios with negative numbers,
    451  // and zeros, and with numbers near 2^32 and 2^64 (to check overflow).
    452  should_not_apply("(aspect-ratio: 0/1)");
    453  should_not_apply("(aspect-ratio: 1/0)");
    454  should_not_apply("(aspect-ratio: -1/1)");
    455  should_not_apply("(aspect-ratio: 1/-1)");
    456  should_not_apply("(aspect-ratio: -1/-1)");
    457  should_not_apply("(aspect-ratio: -59/-80)");
    458  should_not_apply("(aspect-ratio: 4294967295/4294967295)");
    459  should_not_apply("(aspect-ratio: 4294967297/4294967297)");
    460  should_not_apply("(aspect-ratio: 18446744073709560000/18446744073709560000)");
    461 
    462  // Test min and max aspect ratios.
    463  should_apply("(min-aspect-ratio: 59/80)");
    464  should_apply("(min-aspect-ratio: 58/80)");
    465  should_apply("(min-aspect-ratio: 59/81)");
    466  should_not_apply("(min-aspect-ratio: 60/80)");
    467  should_not_apply("(min-aspect-ratio: 59/79)");
    468  expression_should_not_be_known("min-aspect-ratio");
    469 
    470  should_apply("(max-aspect-ratio: 59/80)");
    471  should_not_apply("(max-aspect-ratio: 58/80)");
    472  should_not_apply("(max-aspect-ratio: 59/81)");
    473  should_apply("(max-aspect-ratio: 60/80)");
    474  should_apply("(max-aspect-ratio: 59/79)");
    475  expression_should_not_be_known("max-aspect-ratio");
    476 
    477  var real_dar = device_width + "/" + device_height;
    478  var high_dar_1 = (device_width + 1) + "/" + device_height;
    479  var high_dar_2 = device_width + "/" + (device_height - 1);
    480  var low_dar_1 = (device_width - 1) + "/" + device_height;
    481  var low_dar_2 = device_width + "/" + (device_height + 1);
    482  should_apply("(device-aspect-ratio: " + real_dar + ")");
    483  should_apply("not all and (device-aspect-ratio: " + high_dar_1 + ")");
    484  should_not_apply("all and (device-aspect-ratio: " + high_dar_2 + ")");
    485  should_not_apply("all and (device-aspect-ratio: " + low_dar_1 + ")");
    486  should_apply("not all and (device-aspect-ratio: " + low_dar_2 + ")");
    487  should_apply("(device-aspect-ratio)");
    488 
    489  should_apply("(min-device-aspect-ratio: " + real_dar + ")");
    490  should_not_apply("all and (min-device-aspect-ratio: " + high_dar_1 + ")");
    491  should_apply("not all and (min-device-aspect-ratio: " + high_dar_2 + ")");
    492  should_not_apply("not all and (min-device-aspect-ratio: " + low_dar_1 + ")");
    493  should_apply("all and (min-device-aspect-ratio: " + low_dar_2 + ")");
    494  expression_should_not_be_known("min-device-aspect-ratio");
    495 
    496  should_apply("all and (max-device-aspect-ratio: " + real_dar + ")");
    497  should_apply("(max-device-aspect-ratio: " + high_dar_1 + ")");
    498  should_apply("(max-device-aspect-ratio: " + high_dar_2 + ")");
    499  should_not_apply("all and (max-device-aspect-ratio: " + low_dar_1 + ")");
    500  should_apply("not all and (max-device-aspect-ratio: " + low_dar_2 + ")");
    501  expression_should_not_be_known("max-device-aspect-ratio");
    502 
    503  // Tests for -moz- & -webkit versions of "device-pixel-ratio"
    504  // (Note that the vendor prefixes go in different places.)
    505  test_device_pixel_ratio("-moz-device-pixel-ratio",
    506                          "min--moz-device-pixel-ratio",
    507                          "max--moz-device-pixel-ratio");
    508  test_device_pixel_ratio("-webkit-device-pixel-ratio",
    509                          "-webkit-min-device-pixel-ratio",
    510                          "-webkit-max-device-pixel-ratio");
    511 
    512  // Make sure that we don't accidentally start accepting *unprefixed*
    513  // "device-pixel-ratio" expressions:
    514  expression_should_be_known("-webkit-device-pixel-ratio: 1.0");
    515  expression_should_not_be_known("device-pixel-ratio: 1.0");
    516  expression_should_be_known("-webkit-min-device-pixel-ratio: 1.0");
    517  expression_should_not_be_known("min-device-pixel-ratio: 1.0");
    518  expression_should_be_known("-webkit-max-device-pixel-ratio: 1.0");
    519  expression_should_not_be_known("max-device-pixel-ratio: 1.0");
    520 
    521  should_apply("(-webkit-transform-3d)");
    522 
    523  features = [ "max-aspect-ratio", "device-aspect-ratio" ];
    524  for (i in features) {
    525    feature = features[i];
    526    expression_should_be_known(feature + ": 1/1");
    527    expression_should_be_known(feature + ": 1  /1");
    528    expression_should_be_known(feature + ": 1  / \t\n1");
    529    expression_should_be_known(feature + ": 1/\r1");
    530    expression_should_be_known(feature + ": 1");
    531    expression_should_be_known(feature + ": 0.5");
    532    expression_should_be_known(feature + ": 1.0/1");
    533    expression_should_be_known(feature + ": 1/1.0");
    534    expression_should_be_known(feature + ": 1.0/1.0");
    535    expression_should_be_known(feature + ": 1.5/1.2");
    536    expression_should_be_known(feature + ": 1.5");
    537    expression_should_be_known(feature + ": calc(1.2 * 1.3)");
    538    expression_should_be_known(feature + ": 1.1/calc(2.2 * 2.3)");
    539    expression_should_be_known(feature + ": calc(1.2 * 1.3)/2.2");
    540    expression_should_be_known(feature + ": calc(1.2 * 1.3)/calc(2.2 * 2.3)");
    541    expression_should_be_known(feature + ": 0/1");
    542    expression_should_be_known(feature + ": 1/0");
    543    expression_should_be_known(feature + ": 0/0");
    544    expression_should_not_be_known(feature + ": -1/1");
    545    expression_should_not_be_known(feature + ": 1/-1");
    546    expression_should_not_be_known(feature + ": -1/-1");
    547    expression_should_not_be_known(feature + ": -1/-1");
    548    expression_should_not_be_known(feature + ": -1/-1");
    549    expression_should_not_be_known(feature + ": invalid");
    550    expression_should_not_be_known(feature + ": 1 / invalid");
    551    expression_should_not_be_known(feature + ": 1 invalid");
    552  }
    553 
    554  var is_monochrome = query_applies("all and (min-monochrome: 1)");
    555  test_serialization("all and (min-monochrome: 1)", true, is_monochrome);
    556  var is_color = query_applies("all and (min-color: 1)");
    557  test_serialization("all and (min-color: 1)", true, is_color);
    558  isnot(is_monochrome, is_color, "should be either monochrome or color");
    559 
    560  function depth_query(prefix, depth) {
    561    return "all and (" + prefix + (is_color ? "color" : "monochrome") +
    562           ":" + depth + ")";
    563  }
    564 
    565  var depth = 0;
    566  do {
    567    if (depth > 50) {
    568      ok(false, "breaking from loop, depth > 50");
    569      break;
    570    }
    571  } while (query_applies(depth_query("min-", ++depth)));
    572  --depth;
    573 
    574  should_apply(depth_query("", depth));
    575  should_not_apply(depth_query("", depth - 1));
    576  should_not_apply(depth_query("", depth + 1));
    577  should_apply(depth_query("max-", depth));
    578  should_not_apply(depth_query("max-", depth - 1));
    579  should_apply(depth_query("max-", depth + 1));
    580 
    581  (is_color ? should_apply : should_not_apply)("all and (color)");
    582  expression_should_not_be_known("max-color");
    583  expression_should_not_be_known("min-color");
    584  (is_color ? should_not_apply : should_apply)("all and (monochrome)");
    585  expression_should_not_be_known("max-monochrome");
    586  expression_should_not_be_known("min-monochrome");
    587  (is_color ? should_apply : should_not_apply)("not all and (monochrome)");
    588  (is_color ? should_not_apply : should_apply)("not all and (color)");
    589  (is_color ? should_apply : should_not_apply)("only all and (color)");
    590  (is_color ? should_not_apply : should_apply)("only all and (monochrome)");
    591 
    592  features = [ "color", "min-monochrome", "max-color-index" ];
    593  for (i in features) {
    594    feature = features[i];
    595    expression_should_be_known(feature + ": 1");
    596    expression_should_be_known(feature + ": 327");
    597    expression_should_be_known(feature + ": 0");
    598    expression_should_be_known(feature + ": -1");
    599    expression_should_not_be_known(feature + ": 1.0");
    600    expression_should_not_be_known(feature + ": 1/1");
    601  }
    602 
    603  // Presume that we never support indexed color (at least not usefully
    604  // enough to call it indexed color).
    605  should_apply("(color-index: 0)");
    606  should_not_apply("(color-index: 1)");
    607  should_apply("(min-color-index: 0)");
    608  should_not_apply("(min-color-index: 1)");
    609  should_apply("(max-color-index: 0)");
    610  should_apply("(max-color-index: 1)");
    611  should_apply("(max-color-index: 157)");
    612 
    613  features = [ "resolution", "min-resolution", "max-resolution" ];
    614  for (i in features) {
    615    feature = features[i];
    616    expression_should_be_known(feature + ": 3dpi");
    617    expression_should_be_known(feature + ":3dpi");
    618    expression_should_be_known(feature + ": 3.0dpi");
    619    expression_should_be_known(feature + ": 3.4dpi");
    620    expression_should_be_known(feature + "\t: 120dpcm");
    621    expression_should_be_known(feature + ": 1dppx");
    622    expression_should_be_known(feature + ": 1x");
    623    expression_should_be_known(feature + ": 1.5dppx");
    624    expression_should_be_known(feature + ": 1.5x");
    625    expression_should_be_known(feature + ": 2.0dppx");
    626    expression_should_be_known(feature + ": 0dpi");
    627    expression_should_be_known(feature + ": 0dppx");
    628    expression_should_be_known(feature + ": 0x");
    629    expression_should_not_be_known(feature + ": -3dpi");
    630  }
    631 
    632  // Find the resolution using max-resolution
    633  var resolution = 0;
    634  do {
    635    ++resolution;
    636    if (resolution > 10000) {
    637      ok(false, "resolution greater than 10000dpi???");
    638      break;
    639    }
    640  } while (!query_applies("(max-resolution: " + resolution + "dpi)"));
    641 
    642  // resolution should now be Math.ceil() of the actual resolution.
    643  var dpi_high;
    644  var dpi_low = resolution - 1;
    645  if (query_applies("(min-resolution: " + resolution + "dpi)")) {
    646    // It's exact!
    647    should_apply("(resolution: " + resolution + "dpi)");
    648    should_apply("(resolution: " + Math.floor(resolution/96) + "dppx)");
    649    should_apply("(resolution: " + Math.floor(resolution/96) + "x)");
    650    should_not_apply("(resolution: " + (resolution + 1) + "dpi)");
    651    should_not_apply("(resolution: " + (resolution - 1) + "dpi)");
    652    dpi_high = resolution + 1;
    653  } else {
    654    // We have no way to test resolution applying since it need not be
    655    // an integer.
    656    should_not_apply("(resolution: " + resolution + "dpi)");
    657    should_not_apply("(resolution: " + (resolution - 1) + "dpi)");
    658    dpi_high = resolution;
    659  }
    660 
    661  should_apply("(min-resolution: " + dpi_low + "dpi)");
    662  should_not_apply("not all and (min-resolution: " + dpi_low + "dpi)");
    663  should_apply("not all and (min-resolution: " + dpi_high + "dpi)");
    664  should_not_apply("all and (min-resolution: " + dpi_high + "dpi)");
    665 
    666  // Test dpcm units based on what we computed in dpi.
    667  var dpcm_high = Math.ceil(dpi_high / 2.54);
    668  var dpcm_low = Math.floor(dpi_low / 2.54);
    669  should_apply("(min-resolution: " + dpcm_low + "dpcm)");
    670  should_apply("(max-resolution: " + dpcm_high + "dpcm)");
    671  should_not_apply("(max-resolution: " + dpcm_low + "dpcm)");
    672  should_apply("not all and (min-resolution: " + dpcm_high + "dpcm)");
    673 
    674  expression_should_be_known("scan");
    675  expression_should_be_known("scan: progressive");
    676  expression_should_be_known("scan:interlace");
    677  expression_should_not_be_known("min-scan:interlace");
    678  expression_should_not_be_known("scan: 1");
    679  expression_should_not_be_known("max-scan");
    680  expression_should_not_be_known("max-scan: progressive");
    681  // Assume we don't support tv devices.
    682  should_not_apply("(scan)");
    683  should_not_apply("(scan: progressive)");
    684  should_not_apply("(scan: interlace)");
    685  should_apply("not all and (scan)");
    686  should_apply("not all and (scan: progressive)");
    687  should_apply("not all and (scan: interlace)");
    688 
    689  expression_should_be_known("grid");
    690  expression_should_be_known("grid: 0");
    691  expression_should_be_known("grid: 1");
    692  expression_should_be_known("grid: 1");
    693  expression_should_not_be_known("min-grid");
    694  expression_should_not_be_known("min-grid:0");
    695  expression_should_not_be_known("max-grid: 1");
    696  expression_should_not_be_known("grid: 2");
    697  expression_should_not_be_known("grid: -1");
    698 
    699  // Assume we don't support grid devices
    700  should_not_apply("(grid)");
    701  should_apply("(grid: 0)");
    702  should_not_apply("(grid: 1)");
    703  should_not_apply("(grid: 2)");
    704  should_not_apply("(grid: -1)");
    705 
    706  for (let toggle of CHROME_ONLY_TOGGLES) {
    707    expression_should_not_be_known(toggle);
    708    expression_should_not_be_known(toggle + ": 1");
    709    expression_should_not_be_known(toggle + ": 0");
    710    expression_should_not_be_known(toggle + ": -1");
    711    expression_should_not_be_known(toggle + ": true");
    712    expression_should_not_be_known(toggle + ": false");
    713  }
    714 
    715  for (let query of CHROME_ONLY_QUERIES) {
    716    expression_should_not_be_known(query);
    717  }
    718 
    719  expression_should_be_known("prefers-contrast");
    720  expression_should_be_known("prefers-contrast: more");
    721  expression_should_be_known("prefers-contrast: less");
    722  expression_should_be_known("prefers-contrast: custom");
    723  expression_should_be_known("prefers-contrast: no-preference");
    724 
    725  expression_should_be_known("forced-colors");
    726  expression_should_be_known("forced-colors: none");
    727  expression_should_be_known("forced-colors: active");
    728 
    729  // OpenType SVG media features
    730  expression_should_not_be_known("(-moz-is-glyph)");
    731  expression_should_not_be_known("not (-moz-is-glyph)");
    732  expression_should_not_be_known("only (-moz-is-glyph)");
    733  expression_should_not_be_known("all and (-moz-is-glyph)");
    734  expression_should_not_be_known("not all and (-moz-is-glyph)");
    735  expression_should_not_be_known("only all and (-moz-is-glyph)");
    736 
    737  expression_should_not_be_known("(-moz-is-glyph:0)");
    738  expression_should_not_be_known("not (-moz-is-glyph:0)");
    739  expression_should_not_be_known("only (-moz-is-glyph:0)");
    740  expression_should_not_be_known("all and (-moz-is-glyph:0)");
    741  expression_should_not_be_known("not all and (-moz-is-glyph:0)");
    742  expression_should_not_be_known("only all and (-moz-is-glyph:0)");
    743 
    744  expression_should_not_be_known("(-moz-is-glyph:1)");
    745  expression_should_not_be_known("not (-moz-is-glyph:1)");
    746  expression_should_not_be_known("only (-moz-is-glyph:1)");
    747  expression_should_not_be_known("all and (-moz-is-glyph:1)");
    748  expression_should_not_be_known("not all and (-moz-is-glyph:1)");
    749  expression_should_not_be_known("only all and (-moz-is-glyph:1)");
    750 
    751  expression_should_not_be_known("(min--moz-is-glyph:0)");
    752  expression_should_not_be_known("(max--moz-is-glyph:0)");
    753  expression_should_not_be_known("(min--moz-is-glyph:1)");
    754  expression_should_not_be_known("(max--moz-is-glyph:1)");
    755 
    756  should_not_apply("not all and (-moz-is-glyph)");
    757  should_not_apply("(-moz-is-glyph:0)");
    758  should_not_apply("not all and (-moz-is-glyph:1)");
    759  should_not_apply("only all and (-moz-is-glyph:0)");
    760  should_not_apply("(-moz-is-glyph)");
    761  should_not_apply("(-moz-is-glyph:1)");
    762  should_not_apply("not all and (-moz-is-glyph:0)");
    763  should_not_apply("only all and (-moz-is-glyph:1)");
    764 
    765  // Resource documents (UA-only).
    766  expression_should_not_be_known("(-moz-is-resource-document)");
    767 
    768  // Parsing tests
    769  // bug 454227
    770  should_apply_unbalanced("(orientation");
    771  should_not_apply_unbalanced("not all and (orientation");
    772  should_not_apply_unbalanced("(orientation:");
    773  should_apply_unbalanced("all,(orientation:");
    774  should_not_apply_unbalanced("(orientation:,all");
    775  should_apply_unbalanced("not all and (grid");
    776  should_not_apply_unbalanced("only all and (grid");
    777  should_not_apply_unbalanced("(grid");
    778  should_apply_unbalanced("all,(grid");
    779  should_not_apply_unbalanced("(grid,all");
    780  // bug 454226
    781  should_apply(",all");
    782  should_apply("all,");
    783  should_apply(",all,");
    784  should_apply("all,badmedium");
    785  should_apply("badmedium,all");
    786  should_not_apply(",badmedium,");
    787  should_apply("all,(badexpression)");
    788  should_apply("(badexpression),all");
    789  should_not_apply("(badexpression),badmedium");
    790  should_not_apply("badmedium,(badexpression)");
    791  should_apply("all,[badsyntax]");
    792  should_apply("[badsyntax],all");
    793  should_not_apply("badmedium,[badsyntax]");
    794  should_not_apply("[badsyntax],badmedium");
    795  // bug 528096
    796  should_not_apply_unbalanced("((resolution),all");
    797  should_not_apply_unbalanced("(resolution(),all");
    798  should_not_apply_unbalanced("(resolution (),all");
    799  should_not_apply_unbalanced("(resolution:(),all");
    800 
    801  for (let rangeFeature of ["dynamic-range", "video-dynamic-range"]) {
    802    should_apply("(" + rangeFeature + ": standard)");
    803    expression_should_be_known("(" + rangeFeature + ": high)");
    804    expression_should_not_be_known("(" + rangeFeature + ": low)");
    805  }
    806 
    807  handle_posted_items();
    808 }
    809 
    810 /*
    811 * The cloning tests have to post tests that wait for onload.  However,
    812 * we also make a bunch of state changes during the tests above.  So we
    813 * always change state using the change_state call, with both makes the
    814 * change immediately and posts an item in the same queue so that we
    815 * make the same state change again later.
    816 */
    817 
    818 var posted_items = [];
    819 
    820 function change_state(func)
    821 {
    822  func();
    823  posted_items.push({state: func});
    824 }
    825 
    826 function post_clone_test(srcdoc, testfunc)
    827 {
    828  posted_items.push({srcdoc, testfunc});
    829 }
    830 
    831 function handle_posted_items()
    832 {
    833  if (posted_items.length == 0) {
    834    SimpleTest.finish();
    835    return;
    836  }
    837 
    838  if ("state" in posted_items[0]) {
    839    var item = posted_items.shift();
    840    item.state();
    841    handle_posted_items();
    842    return;
    843  }
    844 
    845  var srcdoc = posted_items[0].srcdoc;
    846  iframe.onload = handle_iframe_onload;
    847  iframe.srcdoc = srcdoc;
    848 }
    849 
    850 function handle_iframe_onload(event)
    851 {
    852  if (event.target != iframe)
    853    return;
    854 
    855  var item = posted_items.shift();
    856  item.testfunc();
    857  handle_posted_items();
    858 }
    859 
    860 </script>
    861 </pre>
    862 </body>
    863 </html>