Correct handling of unitless zero in calc() expressions. (Bug 595648) r=bzbarsky a=blocking2.0:betaN+
authorL. David Baron <dbaron@dbaron.org>
Thu, 30 Dec 2010 12:59:33 -0500
changeset 59740 97e0776740d37912dbcf49fd8e63038d2ad24b3a
parent 59739 fe4489fb36aba79563f01fd05c2751f021399414
child 59741 b725b46f03ed0f7c257de2a523f474662321632a
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbzbarsky, blocking2
bugs595648
milestone2.0b9pre
Correct handling of unitless zero in calc() expressions. (Bug 595648) r=bzbarsky a=blocking2.0:betaN+ This ensures that we treat a unitless zero as a number rather than a length inside of calc() expressions. This causes both the acceptance of previously-rejected expressions (such as -moz-calc(0 * 1em)) and the rejection of previously-accepted ones (such as -moz-calc(0 + 1em)).
layout/style/nsCSSParser.cpp
layout/style/test/property_database.js
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -7128,17 +7128,23 @@ CSSParserImpl::ParseCalcTerm(nsCSSValue&
         !ExpectSymbol(')', PR_TRUE)) {
       SkipUntil(')');
       return PR_FALSE;
     }
     return PR_TRUE;
   }
   // ... or just a value
   UngetToken();
-  if (!ParseVariant(aValue, aVariantMask, nsnull)) {
+  // Always pass VARIANT_NUMBER to ParseVariant so that unitless zero
+  // always gets picked up 
+  if (!ParseVariant(aValue, aVariantMask | VARIANT_NUMBER, nsnull)) {
+    return PR_FALSE;
+  }
+  // ...and do the VARIANT_NUMBER check ourselves.
+  if (!(aVariantMask & VARIANT_NUMBER) && aValue.GetUnit() == eCSSUnit_Number) {
     return PR_FALSE;
   }
   // If we did the value parsing, we need to adjust aVariantMask to
   // reflect which option we took (see above).
   if (aVariantMask & VARIANT_NUMBER) {
     if (aValue.GetUnit() == eCSSUnit_Number) {
       aVariantMask = VARIANT_NUMBER;
     } else {
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -524,16 +524,32 @@ var gCSSProperties = {
 			"-moz-calc((4 / 3) * 2em)",
 
 			"-moz-calc(2em / (4 * 3))",
 			"-moz-calc(2em * (4 / 3))",
 			"-moz-calc(2em * (4 * 3))",
 			"-moz-calc(2em / (4 / 3))",
 			"-moz-calc(4 * (2em / 3))",
 
+			// Valid cases with unitless zero (which is never
+			// a length).
+			"-moz-calc(0 * 2em)",
+			"-moz-calc(2em * 0)",
+			"-moz-calc(3em + 0 * 2em)",
+			"-moz-calc(3em + 2em * 0)",
+			"-moz-calc((0 + 2) * 2em)",
+			"-moz-calc((2 + 0) * 2em)",
+			// And test zero lengths while we're here.
+			"-moz-calc(2 * 0px)",
+			"-moz-calc(0 * 0px)",
+			"-moz-calc(2 * 0em)",
+			"-moz-calc(0 * 0em)",
+			"-moz-calc(0px * 0)",
+			"-moz-calc(0px * 2)",
+
 		],
 		invalid_values: [ "20", "-1px", "red", "50%",
 			/* invalid calc() values */
 			"-moz-calc(2em+ 2px)",
 			"-moz-calc(2em +2px)",
 			"-moz-calc(2em+2px)",
 			"-moz-calc(2em- 2px)",
 			"-moz-calc(2em -2px)",
@@ -555,16 +571,30 @@ var gCSSProperties = {
 			"-moz-calc(5 * 5)",
 			"-moz-calc(5em * 5em)",
 			"-moz-calc(5em / 5em * 5em)",
 
 			"-moz-calc(4 * 3 / 2em)",
 			"-moz-calc((4 * 3) / 2em)",
 			"-moz-calc(4 * (3 / 2em))",
 			"-moz-calc(4 / (3 * 2em))",
+
+			// Tests for handling of unitless zero, which cannot
+			// be a length inside calc().
+			"-moz-calc(0)",
+			"-moz-calc(0 + 2em)",
+			"-moz-calc(2em + 0)",
+			"-moz-calc(0 * 2)",
+			"-moz-calc(2 * 0)",
+			"-moz-calc(1 * (2em + 0))",
+			"-moz-calc((2em + 0))",
+			"-moz-calc((2em + 0) * 1)",
+			"-moz-calc(1 * (0 + 2em))",
+			"-moz-calc((0 + 2em))",
+			"-moz-calc((0 + 2em) * 1)",
 		]
 	},
 	"-moz-column-rule-style": {
 		domProp: "MozColumnRuleStyle",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "solid", "hidden", "ridge", "groove", "inset", "outset", "double", "dotted", "dashed" ],