Make min-/max- prefixed media features without values be parse errors, per http://lists.w3.org/Archives/Public/www-style/2008Sep/0002.html . (Bug 453759) r+sr=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Sat, 06 Sep 2008 07:04:28 -0700
changeset 18891 580343716b2de847b871e7655f41c4018544ed82
parent 18890 df134eac2ff1103e5d279de405792b950e242f5d
child 18892 5cb6b3b6af82642b0fb875933ee8e2e8827538f4
push idunknown
push userunknown
push dateunknown
bugs453759
milestone1.9.1b1pre
Make min-/max- prefixed media features without values be parse errors, per http://lists.w3.org/Archives/Public/www-style/2008Sep/0002.html . (Bug 453759) r+sr=bzbarsky
dom/locales/en-US/chrome/layout/css.properties
layout/style/nsCSSParser.cpp
layout/style/test/test_media_queries.html
--- a/dom/locales/en-US/chrome/layout/css.properties
+++ b/dom/locales/en-US/chrome/layout/css.properties
@@ -128,9 +128,10 @@ PEInaccessibleProperty2=Cannot specify v
 PECommentEOF=end of comment
 SEUnterminatedString=Found unclosed string '%1$S'.
 PEFontDescExpected=Expected font descriptor but found '%1$S'.
 PEUnknownFontDesc=Unknown descriptor '%1$S' in @font-face rule.
 PEMQExpectedExpressionStart=Expected '(' to start media query expression but found '%1$S'.
 PEMQExpressionEOF=contents of media query expression
 PEMQExpectedFeatureName=Expected media feature name but found '%1$S'.
 PEMQExpectedFeatureNameEnd=Expected ':' or ')' after media feature name but found '%1$S'.
+PEMQNoMinMaxWithoutValue=Media features with min- or max- must have a value.
 PEMQExpectedFeatureValue=Found invalid value for media feature.
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1654,17 +1654,22 @@ PRBool CSSParserImpl::ParseMediaQueryExp
   if (eCSSToken_Symbol != mToken.mType ||
       (mToken.mSymbol != PRUnichar(':') && mToken.mSymbol != PRUnichar(')'))) {
     REPORT_UNEXPECTED_TOKEN(PEMQExpectedFeatureNameEnd);
     SkipUntil(aErrorCode, ')');
     return PR_FALSE;
   }
 
   if (mToken.mSymbol == PRUnichar(')')) {
-    // All query expressions can be given without a value.
+    // Query expressions for any feature can be given without a value.
+    // However, min/max prefixes are not allowed.
+    if (expr->mRange != nsMediaExpression::eEqual) {
+      REPORT_UNEXPECTED(PEMQNoMinMaxWithoutValue);
+      return PR_FALSE;
+    }
     expr->mValue.Reset();
     return PR_TRUE;
   }
 
   PRBool rv;
   switch (feature->mValueType) {
     case nsMediaFeature::eLength:
       rv = ParsePositiveVariant(aErrorCode, expr->mValue,
--- a/layout/style/test/test_media_queries.html
+++ b/layout/style/test/test_media_queries.html
@@ -98,26 +98,16 @@ function run() {
        "expression " + e + " should be parseable");
   }
 
   function expression_should_not_be_parseable(e) {
     ok(!expression_is_parseable(e),
        "expression " + e + " should not be parseable");
   }
 
-  function todo_expression_should_be_parseable(e) {
-    todo(expression_is_parseable(e),
-         "expression " + e + " should be parseable");
-  }
-
-  function todo_expression_should_not_be_parseable(e) {
-    todo(!expression_is_parseable(e),
-         "expression " + e + " should not be parseable");
-  }
-
   // The no-type syntax doesn't mix with the not and only keywords.
   query_should_be_parseable("(orientation)");
   query_should_not_be_parseable("not (orientation)");
   query_should_not_be_parseable("only (orientation)");
   query_should_be_parseable("all and (orientation)");
   query_should_be_parseable("not all and (orientation)");
   query_should_be_parseable("only all and (orientation)");
 
@@ -134,16 +124,18 @@ function run() {
     expression_should_be_parseable(feature + ": 1px");
     expression_should_be_parseable(feature + ": 0.001mm");
     expression_should_be_parseable(feature + ": 100000px");
     expression_should_not_be_parseable(feature + ": -1px");
     expression_should_not_be_parseable("min-" + feature + ": -1px");
     expression_should_not_be_parseable("max-" + feature + ": -1px");
     expression_should_not_be_parseable(feature + ": -0.00001mm");
     expression_should_not_be_parseable(feature + ": -100000em");
+    expression_should_not_be_parseable("min-" + feature);
+    expression_should_not_be_parseable("max-" + feature);
   }
 
   var content_div = document.getElementById("content");
   content_div.style.font = "-moz-initial";
   var em_size =
     getComputedStyle(content_div, "").fontSize.match(/^(\d+)px$/)[1];
 
   // in this test, assume the common underlying implementation is correct
@@ -227,51 +219,57 @@ function run() {
   should_not_apply("(aspect-ratio: 59/79)");
   should_apply("(aspect-ratio: 177/240)");
   should_apply("(aspect-ratio: 413/560)");
   should_apply("(aspect-ratio: 5900/8000)");
   should_not_apply("(aspect-ratio: 5901/8000)");
   should_not_apply("(aspect-ratio: 5899/8000)");
   should_not_apply("(aspect-ratio: 5900/8001)");
   should_not_apply("(aspect-ratio: 5900/7999)");
+  should_apply("(aspect-ratio)");
 
   should_apply("(min-aspect-ratio: 59/80)");
   should_apply("(min-aspect-ratio: 58/80)");
   should_apply("(min-aspect-ratio: 59/81)");
   should_not_apply("(min-aspect-ratio: 60/80)");
   should_not_apply("(min-aspect-ratio: 59/79)");
+  expression_should_not_be_parseable("min-aspect-ratio");
 
   should_apply("(max-aspect-ratio: 59/80)");
   should_not_apply("(max-aspect-ratio: 58/80)");
   should_not_apply("(max-aspect-ratio: 59/81)");
   should_apply("(max-aspect-ratio: 60/80)");
   should_apply("(max-aspect-ratio: 59/79)");
+  expression_should_not_be_parseable("max-aspect-ratio");
 
   let real_dar = device_width + "/" + device_height;
   let high_dar_1 = (device_width + 1) + "/" + device_height;
   let high_dar_2 = device_width + "/" + (device_height - 1);
   let low_dar_1 = (device_width - 1) + "/" + device_height;
   let low_dar_2 = device_width + "/" + (device_height + 1);
   should_apply("(device-aspect-ratio: " + real_dar + ")");
   should_apply("not all and (device-aspect-ratio: " + high_dar_1 + ")");
   should_not_apply("all and (device-aspect-ratio: " + high_dar_2 + ")");
   should_not_apply("all and (device-aspect-ratio: " + low_dar_1 + ")");
   should_apply("not all and (device-aspect-ratio: " + low_dar_2 + ")");
+  should_apply("(device-aspect-ratio)");
 
   should_apply("(min-device-aspect-ratio: " + real_dar + ")");
   should_not_apply("all and (min-device-aspect-ratio: " + high_dar_1 + ")");
   should_apply("not all and (min-device-aspect-ratio: " + high_dar_2 + ")");
   should_not_apply("not all and (min-device-aspect-ratio: " + low_dar_1 + ")");
   should_apply("all and (min-device-aspect-ratio: " + low_dar_2 + ")");
+  expression_should_not_be_parseable("min-device-aspect-ratio");
 
   should_apply("all and (max-device-aspect-ratio: " + real_dar + ")");
   should_apply("(max-device-aspect-ratio: " + high_dar_1 + ")");
   should_apply("(max-device-aspect-ratio: " + high_dar_2 + ")");
   should_not_apply("all and (max-device-aspect-ratio: " + low_dar_1 + ")");
   should_apply("not all and (max-device-aspect-ratio: " + low_dar_2 + ")");
+  expression_should_not_be_parseable("max-device-aspect-ratio");
 
   for each (let feature in [ "max-aspect-ratio", "device-aspect-ratio" ]) {
     expression_should_be_parseable(feature + ": 1/1");
     expression_should_be_parseable(feature + ": 1  /1");
     expression_should_be_parseable(feature + ": 1  / \t\n1");
     expression_should_be_parseable(feature + ": 1/\r1");
     expression_should_not_be_parseable(feature + ": 1");
     expression_should_not_be_parseable(feature + ": 0.5");
@@ -307,33 +305,25 @@ function run() {
   should_apply(depth_query("", depth));
   should_not_apply(depth_query("", depth - 1));
   should_not_apply(depth_query("", depth + 1));
   should_apply(depth_query("max-", depth));
   should_not_apply(depth_query("max-", depth - 1));
   should_apply(depth_query("max-", depth + 1));
 
   (is_color ? should_apply : should_not_apply)("all and (color)");
-  (is_color ? should_apply : should_not_apply)("all and (max-color)");
-  (is_color ? should_apply : should_not_apply)("all and (min-color)");
+  expression_should_not_be_parseable("max-color");
+  expression_should_not_be_parseable("min-color");
   (is_color ? should_not_apply : should_apply)("all and (monochrome)");
-  (is_color ? should_not_apply : should_apply)("all and (max-monochrome)");
-  (is_color ? should_not_apply : should_apply)("all and (min-monochrome)");
+  expression_should_not_be_parseable("max-monochrome");
+  expression_should_not_be_parseable("min-monochrome");
   (is_color ? should_apply : should_not_apply)("not all and (monochrome)");
-  (is_color ? should_apply : should_not_apply)("not all and (max-monochrome)");
-  (is_color ? should_apply : should_not_apply)("not all and (min-monochrome)");
   (is_color ? should_not_apply : should_apply)("not all and (color)");
-  (is_color ? should_not_apply : should_apply)("not all and (max-color)");
-  (is_color ? should_not_apply : should_apply)("not all and (min-color)");
   (is_color ? should_apply : should_not_apply)("only all and (color)");
-  (is_color ? should_apply : should_not_apply)("only all and (max-color)");
-  (is_color ? should_apply : should_not_apply)("only all and (min-color)");
   (is_color ? should_not_apply : should_apply)("only all and (monochrome)");
-  (is_color ? should_not_apply : should_apply)("only all and (max-monochrome)");
-  (is_color ? should_not_apply : should_apply)("only all and (min-monochrome)");
 
   for each (let feature in [ "color", "min-monochrome", "max-color-index" ]) {
     expression_should_be_parseable(feature + ": 1");
     expression_should_be_parseable(feature + ": 327");
     expression_should_be_parseable(feature + ": 0");
     expression_should_not_be_parseable(feature + ": 1.0");
     expression_should_not_be_parseable(feature + ": -1");
     expression_should_not_be_parseable(feature + ": 1/1");
@@ -401,29 +391,31 @@ function run() {
   should_apply("not all and (min-resolution: " + dpcm_high + "dpcm)");
 
   expression_should_be_parseable("scan");
   expression_should_be_parseable("scan: progressive");
   expression_should_be_parseable("scan:interlace");
   expression_should_not_be_parseable("min-scan:interlace");
   expression_should_not_be_parseable("scan: 1");
   expression_should_not_be_parseable("max-scan");
+  expression_should_not_be_parseable("max-scan: progressive");
   // Assume we don't support tv devices.
   should_not_apply("(scan)");
   should_not_apply("(scan: progressive)");
   should_not_apply("(scan: interlace)");
   should_apply("not all and (scan)");
   should_apply("not all and (scan: progressive)");
   should_apply("not all and (scan: interlace)");
 
   expression_should_be_parseable("grid");
   expression_should_be_parseable("grid: 0");
   expression_should_be_parseable("grid: 1");
   expression_should_be_parseable("grid: 1");
   expression_should_not_be_parseable("min-grid");
+  expression_should_not_be_parseable("min-grid:0");
   expression_should_not_be_parseable("max-grid: 1");
   expression_should_not_be_parseable("grid: 2");
   expression_should_not_be_parseable("grid: -1");
 
   // Assume we don't support grid devices
   should_not_apply("(grid)");
   should_apply("(grid: 0)");
   should_not_apply("(grid: 1)");