Add support for calc() to the 'min-width' and 'max-width' properties. (Bug 585715) r=bzbarsky a2.0=blocking+

This commit is contained in:
L. David Baron 2010-08-25 12:17:56 +02:00
parent 091d6b7837
commit b99a005c4c
15 changed files with 214 additions and 28 deletions

View File

@ -1954,6 +1954,11 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
// intrinsic minimum width
nscoord result = 0, min = 0;
nscoord maxw;
PRBool haveFixedMaxWidth = GetAbsoluteCoord(styleMaxWidth, maxw);
nscoord minw;
PRBool haveFixedMinWidth = GetAbsoluteCoord(styleMinWidth, minw);
// If we have a specified width (or a specified 'min-width' greater
// than the specified 'max-width', which works out to the same thing),
// don't even bother getting the frame's intrinsic width.
@ -1966,9 +1971,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
// specified widths, but ignore -moz-box-sizing.
boxSizing = NS_STYLE_BOX_SIZING_CONTENT;
} else if (styleWidth.GetUnit() != eStyleUnit_Coord &&
(styleMinWidth.GetUnit() != eStyleUnit_Coord ||
styleMaxWidth.GetUnit() != eStyleUnit_Coord ||
styleMaxWidth.GetCoordValue() > styleMinWidth.GetCoordValue())) {
!(haveFixedMinWidth && haveFixedMaxWidth && maxw <= minw)) {
#ifdef DEBUG_INTRINSIC_WIDTH
++gNoiseIndent;
#endif
@ -2091,8 +2094,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
result = AddPercents(aType, result, pctTotal);
}
nscoord maxw;
if (GetAbsoluteCoord(styleMaxWidth, maxw) ||
if (haveFixedMaxWidth ||
GetIntrinsicCoord(styleMaxWidth, aRenderingContext, aFrame,
PROP_MAX_WIDTH, maxw)) {
maxw = AddPercents(aType, maxw + coordOutsideWidth, pctOutsideWidth);
@ -2100,8 +2102,7 @@ nsLayoutUtils::IntrinsicForContainer(nsIRenderingContext *aRenderingContext,
result = maxw;
}
nscoord minw;
if (GetAbsoluteCoord(styleMinWidth, minw) ||
if (haveFixedMinWidth ||
GetIntrinsicCoord(styleMinWidth, aRenderingContext, aFrame,
PROP_MIN_WIDTH, minw)) {
minw = AddPercents(aType, minw + coordOutsideWidth, pctOutsideWidth);

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<title>max-width: calc() on blocks</title>
<style>
body { width: 500px }
p { background: green; color: white; margin: 1px 0; font-size: 10px; width: 1000px; }
</style>
<p style="max-width: -moz-calc(50% - 3px)">50% - 3px</p>
<p style="max-width: -moz-calc(25% - 3px + 25%)">25% - 3px + 25%</p>
<p style="max-width: -moz-calc(25% - 3px + 12.5% * 2)">25% - 3px + 12.5% * 2</p>
<p style="max-width: -moz-calc(25% - 3px + 12.5%*2)">25% - 3px + 12.5%*2</p>
<p style="max-width: -moz-calc(25% - 3px + 2*12.5%)">25% - 3px + 2*12.5%</p>
<p style="max-width: -moz-calc(25% - 3px + 2 * 12.5%)">25% - 3px + 2 * 12.5%</p>
<p style="max-width: -moz-min(25%, 150px)">min(25%, 150px)</p>
<p style="max-width: -moz-calc(min(25%, 100px))">min(25%, 100px)</p>
<p style="max-width: -moz-calc(max(25%, 150px))">max(25%, 150px)</p>
<p style="max-width: -moz-max(25%, 100px)">max(25%, 100px)</p>
<p style="max-width: -moz-calc(min(25%, 150px) + 5%)">min(25%, 150px) + 5%</p>
<p style="max-width: -moz-calc(min(25%, 100px) + 5%)">min(25%, 100px) + 5%</p>
<p style="max-width: -moz-calc(max(25%, 150px) + 5%)">max(25%, 150px) + 5%</p>
<p style="max-width: -moz-calc(max(25%, 100px) + 5%)">max(25%, 100px) + 5%</p>
<p style="max-width: -moz-calc(min(25%, 150px) - 2em)">min(25%, 150px) - 2em</p>
<p style="max-width: -moz-calc(min(25%, 100px) - 2em)">min(25%, 100px) - 2em</p>
<p style="max-width: -moz-calc(max(25%, 150px) - 2em)">max(25%, 150px) - 2em</p>
<p style="max-width: -moz-calc(max(25%, 100px) - 2em)">max(25%, 100px) - 2em</p>
<p style="max-width: -moz-calc(30% + 20%)">30% + 20%</p>
<p style="max-width: -moz-calc(30% + max(20%, 1px))">30% + max(20%, 1px)</p>
<p style="max-width: -moz-calc(max(25%, 50%))">max(25%, 50%)</p>
<p style="max-width: -moz-calc(min(25%, 50%))">max(25%, 50%)</p>

View File

@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<title>intrinsic width of max-width: calc() on blocks</title>
<style>
body > div { margin: 0 0 1px 0; background: blue; color: white; height: 5px }
</style>
<div style="width: 400px"></div>
<div style="width: 47px"></div>
<div style="width: 47px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>
<div style="width: 50px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>
<div style="width: 50px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>
<div style="width: 400px"></div>

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<title>intrinsic width of max-width: calc() on blocks</title>
<style>
body { font-size: 10px }
body > div { float: left; clear: left;
margin: 0 0 1px 0; background: blue; color: white; height: 5px }
body > div > div { width: 400px }
body > div > div > div { width: 200px }
</style>
<div><div style="max-width: -moz-calc(50% - 3px)"><div></div></div></div>
<div><div style="max-width: -moz-calc(5em - 3px)"><div></div></div></div>
<div><div style="max-width: -moz-calc(max(5em, 0) - 3px)"><div></div></div></div>
<div><div style="max-width: -moz-calc(max(5em, 0%) - 3px)"><div></div></div></div>
<div><div style="max-width: -moz-calc(5em - min(3px, 0%))"><div></div></div></div>
<div><div style="max-width: -moz-calc(5em - min(3px, 0))"><div></div></div></div>
<div><div style="max-width: -moz-calc(5em - 0%)"><div></div></div></div>
<div><div style="max-width: -moz-calc(50%)"><div></div></div></div>
<div><div style="max-width: -moz-calc(50px)"><div></div></div></div>
<div><div style="max-width: -moz-calc(25% + 25%)"><div></div></div></div>
<div><div style="max-width: -moz-calc(min(25%, 50%))"><div></div></div></div>
<div><div style="max-width: -moz-calc(max(25%, 50%))"><div></div></div></div>
<div><div style="max-width: -moz-calc(min(25%, 100px))"><div></div></div></div>
<div><div style="max-width: -moz-calc(max(25%, 100px))"><div></div></div></div>

View File

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<title>min-width: calc() on blocks</title>
<style>
body { width: 500px }
p { background: green; color: white; margin: 1px 0; font-size: 10px; width: 0 }
</style>
<p style="min-width: -moz-calc(50% - 3px)">50% - 3px</p>
<p style="min-width: -moz-calc(25% - 3px + 25%)">25% - 3px + 25%</p>
<p style="min-width: -moz-calc(25% - 3px + 12.5% * 2)">25% - 3px + 12.5% * 2</p>
<p style="min-width: -moz-calc(25% - 3px + 12.5%*2)">25% - 3px + 12.5%*2</p>
<p style="min-width: -moz-calc(25% - 3px + 2*12.5%)">25% - 3px + 2*12.5%</p>
<p style="min-width: -moz-calc(25% - 3px + 2 * 12.5%)">25% - 3px + 2 * 12.5%</p>
<p style="min-width: -moz-min(25%, 150px)">min(25%, 150px)</p>
<p style="min-width: -moz-calc(min(25%, 100px))">min(25%, 100px)</p>
<p style="min-width: -moz-calc(max(25%, 150px))">max(25%, 150px)</p>
<p style="min-width: -moz-max(25%, 100px)">max(25%, 100px)</p>
<p style="min-width: -moz-calc(min(25%, 150px) + 5%)">min(25%, 150px) + 5%</p>
<p style="min-width: -moz-calc(min(25%, 100px) + 5%)">min(25%, 100px) + 5%</p>
<p style="min-width: -moz-calc(max(25%, 150px) + 5%)">max(25%, 150px) + 5%</p>
<p style="min-width: -moz-calc(max(25%, 100px) + 5%)">max(25%, 100px) + 5%</p>
<p style="min-width: -moz-calc(min(25%, 150px) - 2em)">min(25%, 150px) - 2em</p>
<p style="min-width: -moz-calc(min(25%, 100px) - 2em)">min(25%, 100px) - 2em</p>
<p style="min-width: -moz-calc(max(25%, 150px) - 2em)">max(25%, 150px) - 2em</p>
<p style="min-width: -moz-calc(max(25%, 100px) - 2em)">max(25%, 100px) - 2em</p>
<p style="min-width: -moz-calc(30% + 20%)">30% + 20%</p>
<p style="min-width: -moz-calc(30% + max(20%, 1px))">30% + max(20%, 1px)</p>
<p style="min-width: -moz-calc(max(25%, 50%))">max(25%, 50%)</p>
<p style="min-width: -moz-calc(min(25%, 50%))">max(25%, 50%)</p>

View File

@ -0,0 +1,22 @@
<!DOCTYPE HTML>
<title>intrinsic width of min-width: calc() on blocks</title>
<style>
body > div { margin: 0 0 1px 0; background: blue; color: white; height: 5px }
</style>
<div style="width: 1px"></div>
<div style="width: 47px"></div>
<div style="width: 47px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>
<div style="width: 50px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>
<div style="width: 50px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>
<div style="width: 1px"></div>

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<title>intrinsic width of min-width: calc() on blocks</title>
<style>
body { font-size: 10px }
body > div { float: left; clear: left;
margin: 0 0 1px 0; background: blue; color: white; height: 5px }
body > div > div { width: 1px }
body > div > div > div { width: 200px }
</style>
<div><div style="min-width: -moz-calc(50% - 3px)"><div></div></div></div>
<div><div style="min-width: -moz-calc(5em - 3px)"><div></div></div></div>
<div><div style="min-width: -moz-calc(max(5em, 0) - 3px)"><div></div></div></div>
<div><div style="min-width: -moz-calc(max(5em, 0%) - 3px)"><div></div></div></div>
<div><div style="min-width: -moz-calc(5em - min(3px, 0%))"><div></div></div></div>
<div><div style="min-width: -moz-calc(5em - min(3px, 0))"><div></div></div></div>
<div><div style="min-width: -moz-calc(5em - 0%)"><div></div></div></div>
<div><div style="min-width: -moz-calc(50%)"><div></div></div></div>
<div><div style="min-width: -moz-calc(50px)"><div></div></div></div>
<div><div style="min-width: -moz-calc(25% + 25%)"><div></div></div></div>
<div><div style="min-width: -moz-calc(min(25%, 50%))"><div></div></div></div>
<div><div style="min-width: -moz-calc(max(25%, 50%))"><div></div></div></div>
<div><div style="min-width: -moz-calc(min(25%, 100px))"><div></div></div></div>
<div><div style="min-width: -moz-calc(max(25%, 100px))"><div></div></div></div>

View File

@ -1,7 +1,11 @@
== height-block-1.html height-block-1-ref.html
== height-table-1.html height-table-1-ref.html
== max-height-block-1.html max-height-block-1-ref.html
== max-width-block-1.html width-block-1-ref.html
== max-width-block-intrinsic-1.html max-width-block-intrinsic-1-ref.html
== min-height-block-1.html height-block-1-ref.html
== min-width-block-1.html width-block-1-ref.html
== min-width-block-intrinsic-1.html min-width-block-intrinsic-1-ref.html
== width-block-1.html width-block-1-ref.html
== width-block-intrinsic-1.html width-block-intrinsic-1-ref.html
== width-table-auto-1.html width-table-auto-1-ref.html

View File

@ -1,5 +1,5 @@
<!DOCTYPE HTML>
<title>width: calc() on blocks</title>
<title>width: calc() and min-width: calc() on blocks</title>
<style>
body { width: 500px }

View File

@ -5834,13 +5834,13 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
return ParseNonNegativeVariant(aValue, VARIANT_HLPO | VARIANT_CALC,
nsnull);
case eCSSProperty_max_width:
return ParseNonNegativeVariant(aValue, VARIANT_HKLPO,
return ParseNonNegativeVariant(aValue, VARIANT_HKLPO | VARIANT_CALC,
nsCSSProps::kWidthKTable);
case eCSSProperty_min_height:
return ParseNonNegativeVariant(aValue, VARIANT_HLP | VARIANT_CALC,
nsnull);
case eCSSProperty_min_width:
return ParseNonNegativeVariant(aValue, VARIANT_HKLP,
return ParseNonNegativeVariant(aValue, VARIANT_HKLP | VARIANT_CALC,
nsCSSProps::kWidthKTable);
case eCSSProperty_opacity:
return ParseVariant(aValue, VARIANT_HN, nsnull);

View File

@ -5541,11 +5541,11 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
SETCOORD_LPAEH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree);
SetCoord(posData.mMinWidth, pos->mMinWidth, parentPos->mMinWidth,
SETCOORD_LPEH | SETCOORD_INITIAL_ZERO, aContext,
mPresContext, canStoreInRuleTree);
SETCOORD_LPEH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree);
SetCoord(posData.mMaxWidth, pos->mMaxWidth, parentPos->mMaxWidth,
SETCOORD_LPOEH | SETCOORD_INITIAL_NONE, aContext,
mPresContext, canStoreInRuleTree);
SETCOORD_LPOEH | SETCOORD_INITIAL_NONE | SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree);
SetCoord(posData.mHeight, pos->mHeight, parentPos->mHeight,
SETCOORD_LPAH | SETCOORD_INITIAL_AUTO | SETCOORD_STORE_CALC,

View File

@ -1086,9 +1086,9 @@ struct nsStylePosition {
static PRBool ForceCompare() { return PR_TRUE; }
nsStyleSides mOffset; // [reset] coord, percent, auto
nsStyleCoord mWidth; // [reset] coord, percent, enum, auto
nsStyleCoord mMinWidth; // [reset] coord, percent, enum
nsStyleCoord mMaxWidth; // [reset] coord, percent, enum, none
nsStyleCoord mWidth; // [reset] coord, percent, enum, calc, auto
nsStyleCoord mMinWidth; // [reset] coord, percent, enum, calc
nsStyleCoord mMaxWidth; // [reset] coord, percent, enum, calc, none
nsStyleCoord mHeight; // [reset] coord, percent, calc, auto
nsStyleCoord mMinHeight; // [reset] coord, percent, calc
nsStyleCoord mMaxHeight; // [reset] coord, percent, calc, none

View File

@ -1782,7 +1782,14 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
prerequisites: { "display": "block" },
initial_values: [ "none" ],
other_values: [ "30px", "50%", "0", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available" ],
other_values: [ "30px", "50%", "0", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
"-moz-calc(2px)",
"-moz-calc(50%)",
"-moz-calc(3*25px)",
"-moz-calc(25px*3)",
"-moz-calc(3*25px + 50%)",
"-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "auto" ]
},
"min-height": {
@ -1807,7 +1814,14 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND,
prerequisites: { "display": "block" },
initial_values: [ "0" ],
other_values: [ "30px", "50%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available" ],
other_values: [ "30px", "50%", "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
"-moz-calc(2px)",
"-moz-calc(50%)",
"-moz-calc(3*25px)",
"-moz-calc(25px*3)",
"-moz-calc(3*25px + 50%)",
"-moz-min(30%, 30em,200px, min(500px ,40em))",
],
invalid_values: [ "auto", "none" ]
},
"opacity": {

View File

@ -190,6 +190,7 @@ GetWidthInfo(nsIRenderingContext *aRenderingContext,
if (p < prefPercent)
prefPercent = p;
}
// treat calc() on max-width just like 'none'.
nsStyleCoord minWidth(stylePos->mMinWidth);
if (minWidth.GetUnit() == eStyleUnit_Enumerated) {
@ -215,6 +216,7 @@ GetWidthInfo(nsIRenderingContext *aRenderingContext,
if (p > prefPercent)
prefPercent = p;
}
// treat calc() on min-width just like '0'.
// XXX Should col frame have border/padding considered?
if (aIsCell) {

View File

@ -773,23 +773,28 @@ nsIBox::AddCSSMinSize(nsBoxLayoutState& aState, nsIBox* aBox, nsSize& aSize,
const nsStylePosition* position = aBox->GetStylePosition();
// same for min size. Unfortunately min size is always set to 0. So for now
// we will assume 0 means not set.
if (position->mMinWidth.GetUnit() == eStyleUnit_Coord) {
nscoord min = position->mMinWidth.GetCoordValue();
if (min && (!aWidthSet || (min > aSize.width && canOverride))) {
// we will assume 0 (as a coord) means not set.
const nsStyleCoord &minWidth = position->mMinWidth;
if ((minWidth.GetUnit() == eStyleUnit_Coord &&
minWidth.GetCoordValue() != 0) ||
(minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) {
nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0);
if (!aWidthSet || (min > aSize.width && canOverride)) {
aSize.width = min;
aWidthSet = PR_TRUE;
}
} else if (position->mMinWidth.GetUnit() == eStyleUnit_Percent) {
NS_ASSERTION(position->mMinWidth.GetPercentValue() == 0.0f,
} else if (minWidth.GetUnit() == eStyleUnit_Percent) {
NS_ASSERTION(minWidth.GetPercentValue() == 0.0f,
"Non-zero percentage values not currently supported");
aSize.width = 0;
aWidthSet = PR_TRUE;
aWidthSet = PR_TRUE; // FIXME: should we really do this for
// nonzero values?
}
// XXX Handle eStyleUnit_Enumerated?
// (Handling the eStyleUnit_Enumerated types requires
// GetPrefSize/GetMinSize methods that don't consider
// (min-/max-/)(width/height) properties.
// calc() with percentage is treated like '0' (unset)
const nsStyleCoord &minHeight = position->mMinHeight;
if ((minHeight.GetUnit() == eStyleUnit_Coord &&
@ -858,10 +863,12 @@ nsIBox::AddCSSMaxSize(nsIBox* aBox, nsSize& aSize, PRBool &aWidthSet, PRBool &aH
// (Handling the eStyleUnit_Enumerated types requires
// GetPrefSize/GetMinSize methods that don't consider
// (min-/max-/)(width/height) properties.)
if (position->mMaxWidth.GetUnit() == eStyleUnit_Coord) {
aSize.width = position->mMaxWidth.GetCoordValue();
const nsStyleCoord maxWidth = position->mMaxWidth;
if (maxWidth.ConvertsToLength()) {
aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0);
aWidthSet = PR_TRUE;
}
// percentages and calc() with percentages are treated like 'none'
const nsStyleCoord &maxHeight = position->mMaxHeight;
if (maxHeight.ConvertsToLength()) {