diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 9bc80d917fce..bffef0ddd22e 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3262,14 +3262,13 @@ nsLayoutUtils::SetFontFromStyle(nsIRenderingContext* aRC, nsStyleContext* aSC)
static PRBool NonZeroStyleCoord(const nsStyleCoord& aCoord)
{
- switch (aCoord.GetUnit()) {
- case eStyleUnit_Percent:
- return aCoord.GetPercentValue() > 0;
- case eStyleUnit_Coord:
- return aCoord.GetCoordValue() > 0;
- default:
- return PR_TRUE;
+ if (aCoord.IsCoordPercentCalcUnit()) {
+ // Since negative results are clamped to 0, check > 0.
+ return nsRuleNode::ComputeCoordPercentCalc(aCoord, nscoord_MAX) > 0 ||
+ nsRuleNode::ComputeCoordPercentCalc(aCoord, 0) > 0;
}
+
+ return PR_TRUE;
}
/* static */ PRBool
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 0fa7bac44a03..cf2f450e96f7 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -749,19 +749,15 @@ nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
nscoord axis =
NS_HALF_CORNER_IS_X(i) ? aFrameSize.width : aFrameSize.height;
- switch (c.GetUnit()) {
- case eStyleUnit_Percent:
- aRadii[i] = (nscoord)(c.GetPercentValue() * axis);
- break;
-
- case eStyleUnit_Coord:
- aRadii[i] = c.GetCoordValue();
- break;
-
- default:
- NS_NOTREACHED("ComputeBorderRadii: bad unit");
+ if (c.IsCoordPercentCalcUnit()) {
+ aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
+ if (aRadii[i] < 0) {
+ // clamp calc()
aRadii[i] = 0;
- break;
+ }
+ } else {
+ NS_NOTREACHED("ComputeBorderRadii: bad unit");
+ aRadii[i] = 0;
}
}
diff --git a/layout/reftests/css-calc/border-radius-1-ref.html b/layout/reftests/css-calc/border-radius-1-ref.html
new file mode 100644
index 000000000000..c906eb97f711
--- /dev/null
+++ b/layout/reftests/css-calc/border-radius-1-ref.html
@@ -0,0 +1,13 @@
+
+
test for border-radius: calc()
+
+
diff --git a/layout/reftests/css-calc/border-radius-1.html b/layout/reftests/css-calc/border-radius-1.html
new file mode 100644
index 000000000000..3dc740f0efe9
--- /dev/null
+++ b/layout/reftests/css-calc/border-radius-1.html
@@ -0,0 +1,13 @@
+
+test for border-radius: calc()
+
+
diff --git a/layout/reftests/css-calc/reftest.list b/layout/reftests/css-calc/reftest.list
index 9bd2ca21ee44..0daf129afd2e 100644
--- a/layout/reftests/css-calc/reftest.list
+++ b/layout/reftests/css-calc/reftest.list
@@ -1,3 +1,4 @@
+== border-radius-1.html border-radius-1-ref.html
== height-block-1.html height-block-1-ref.html
== height-table-1.html height-table-1-ref.html
== margin-block-1.html margin-block-1-ref.html
diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp
index 7873fdb0fec7..de492fb9bc8e 100644
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -5068,13 +5068,13 @@ CSSParserImpl::ParseBoxCornerRadius(nsCSSProperty aPropID)
{
nsCSSValue dimenX, dimenY;
// required first value
- if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP, nsnull))
+ if (! ParseNonNegativeVariant(dimenX, VARIANT_HLP | VARIANT_CALC, nsnull))
return PR_FALSE;
// optional second value (forbidden if first value is inherit/initial)
if (dimenX.GetUnit() != eCSSUnit_Inherit &&
dimenX.GetUnit() != eCSSUnit_Initial) {
- ParseNonNegativeVariant(dimenY, VARIANT_LP, nsnull);
+ ParseNonNegativeVariant(dimenY, VARIANT_LP | VARIANT_CALC, nsnull);
}
if (dimenX == dimenY || dimenY.GetUnit() == eCSSUnit_Null) {
@@ -5098,7 +5098,9 @@ CSSParserImpl::ParseBoxCornerRadii(const nsCSSProperty aPropIDs[])
NS_FOR_CSS_SIDES (side) {
if (! ParseNonNegativeVariant(dimenX.*nsCSSRect::sides[side],
- side > 0 ? VARIANT_LP : VARIANT_HLP, nsnull))
+ (side > 0 ? 0 : VARIANT_INHERIT) |
+ VARIANT_LP | VARIANT_CALC,
+ nsnull))
break;
countX++;
}
@@ -5108,7 +5110,7 @@ CSSParserImpl::ParseBoxCornerRadii(const nsCSSProperty aPropIDs[])
if (ExpectSymbol('/', PR_TRUE)) {
NS_FOR_CSS_SIDES (side) {
if (! ParseNonNegativeVariant(dimenY.*nsCSSRect::sides[side],
- VARIANT_LP, nsnull))
+ VARIANT_LP | VARIANT_CALC, nsnull))
break;
countY++;
}
diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp
index 2f4f7abfcd07..659e81110af5 100644
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5195,7 +5195,8 @@ nsRuleNode::ComputeBorderData(void* aStartStruct,
nsStyleCoord coordX, coordY;
if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
- SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
+ SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
+ SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree)) {
border->mBorderRadius.Set(cx, coordX);
border->mBorderRadius.Set(cy, coordY);
@@ -5406,7 +5407,8 @@ nsRuleNode::ComputeOutlineData(void* aStartStruct,
nsStyleCoord coordX, coordY;
if (SetPairCoords(radius, coordX, coordY, parentX, parentY,
- SETCOORD_LPH | SETCOORD_INITIAL_ZERO,
+ SETCOORD_LPH | SETCOORD_INITIAL_ZERO |
+ SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree)) {
outline->mOutlineRadius.Set(cx, coordX);
outline->mOutlineRadius.Set(cy, coordY);
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
index 906c4d6f6fd0..2a285a1809ef 100644
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -749,7 +749,7 @@ struct nsStyleBorder {
static PRBool ForceCompare() { return PR_FALSE; }
PRBool ImageBorderDiffers() const;
- nsStyleCorners mBorderRadius; // [reset] coord, percent
+ nsStyleCorners mBorderRadius; // [reset] coord, percent, calc
nsStyleSides mBorderImageSplit; // [reset] integer, percent
PRUint8 mFloatEdge; // [reset] see nsStyleConsts.h
PRUint8 mBorderImageHFill; // [reset]
@@ -972,7 +972,7 @@ struct nsStyleOutline {
#endif
static PRBool ForceCompare() { return PR_FALSE; }
- nsStyleCorners mOutlineRadius; // [reset] coord, percent
+ nsStyleCorners mOutlineRadius; // [reset] coord, percent, calc
// Note that this is a specified value. You can get the actual values
// with GetOutlineWidth. You cannot get the computed value directly.
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 413b3620b37e..5bf6524b1faf 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -165,7 +165,18 @@ var gCSSProperties = {
subproperties: [ "-moz-border-radius-bottomleft", "-moz-border-radius-bottomright", "-moz-border-radius-topleft", "-moz-border-radius-topright" ],
initial_values: [ "0", "0px", "0px 0 0 0px" ], /* 0% ? */
other_values: [ "3%", "1px", "2em", "3em 2px", "2pt 3% 4em", "2px 2px 2px 2px", // circular
- "3% / 2%", "1px / 4px", "2em / 1em", "3em 2px / 2px 3em", "2pt 3% 4em / 4pt 1% 5em", "2px 2px 2px 2px / 4px 4px 4px 4px", "1pt / 2pt 3pt", "4pt 5pt / 3pt" // elliptical
+ "3% / 2%", "1px / 4px", "2em / 1em", "3em 2px / 2px 3em", "2pt 3% 4em / 4pt 1% 5em", "2px 2px 2px 2px / 4px 4px 4px 4px", "1pt / 2pt 3pt", "4pt 5pt / 3pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
+ "2px 2px -moz-calc(2px + 1%) 2px",
+ "1px 2px 2px 2px / 2px 2px -moz-calc(2px + 1%) 2px",
],
invalid_values: [ "2px -2px", "inherit 2px", "inherit / 2px", "2px inherit", "2px / inherit", "2px 2px 2px 2px 2px", "1px / 2px 2px 2px 2px 2px" ]
},
@@ -175,7 +186,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px" ], /* 0% ? */
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -185,7 +205,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px" ], /* 0% ? */
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -195,7 +224,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px" ], /* 0% ? */
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -205,7 +243,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px" ], /* 0% ? */
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -607,7 +654,18 @@ var gCSSProperties = {
subproperties: [ "-moz-outline-radius-bottomleft", "-moz-outline-radius-bottomright", "-moz-outline-radius-topleft", "-moz-outline-radius-topright" ],
initial_values: [ "0", "0px", "0%" ],
other_values: [ "3%", "1px", "2em", "3em 2px", "2pt 3% 4em", "2px 2px 2px 2px", // circular
- "3% / 2%", "1px / 4px", "2em / 1em", "3em 2px / 2px 3em", "2pt 3% 4em / 4pt 1% 5em", "2px 2px 2px 2px / 4px 4px 4px 4px", "1pt / 2pt 3pt", "4pt 5pt / 3pt" // elliptical
+ "3% / 2%", "1px / 4px", "2em / 1em", "3em 2px / 2px 3em", "2pt 3% 4em / 4pt 1% 5em", "2px 2px 2px 2px / 4px 4px 4px 4px", "1pt / 2pt 3pt", "4pt 5pt / 3pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
+ "2px 2px -moz-calc(2px + 1%) 2px",
+ "1px 2px 2px 2px / 2px 2px -moz-calc(2px + 1%) 2px",
],
invalid_values: [ "2px -2px", "inherit 2px", "inherit / 2px", "2px inherit", "2px / inherit", "2px 2px 2px 2px 2px", "1px / 2px 2px 2px 2px 2px" ]
},
@@ -617,7 +675,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px", "0%" ],
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -627,7 +694,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px", "0%" ],
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -637,7 +713,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px", "0%" ],
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},
@@ -647,7 +732,16 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "0px", "0%" ],
other_values: [ "3%", "1px", "2em", // circular
- "3% 2%", "1px 4px", "2em 2pt" // elliptical
+ "3% 2%", "1px 4px", "2em 2pt", // elliptical
+ "-moz-calc(2px)",
+ "-moz-calc(50%)",
+ "-moz-calc(3*25px)",
+ "-moz-calc(3*25px) 5px",
+ "5px -moz-calc(3*25px)",
+ "-moz-calc(20%) -moz-calc(3*25px)",
+ "-moz-calc(25px*3)",
+ "-moz-calc(3*25px + 50%)",
+ "-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit" ]
},