Add support for calc() to 'vertical-align' and 'text-indent'. (Bug 585715) r=bzbarsky a2.0=blocking:beta6+

This commit is contained in:
L. David Baron 2010-08-31 12:05:12 -04:00
Родитель 73db7cd5c4
Коммит b221c0b0c0
13 изменённых файлов: 335 добавлений и 186 удалений

Просмотреть файл

@ -715,9 +715,12 @@ nsBlockFrame::GetMinWidth(nsIRenderingContext *aRenderingContext)
} else {
if (!curFrame->GetPrevContinuation() &&
line == curFrame->begin_lines()) {
// Only add text-indent if it has no percentages; using a
// percentage basis of 0 unconditionally would give strange
// behavior for calc(10%-3px).
const nsStyleCoord &indent = GetStyleText()->mTextIndent;
if (indent.GetUnit() == eStyleUnit_Coord)
data.currentLine += indent.GetCoordValue();
if (indent.ConvertsToLength())
data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
}
// XXX Bug NNNNNN Should probably handle percentage text-indent.
@ -790,9 +793,12 @@ nsBlockFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
} else {
if (!curFrame->GetPrevContinuation() &&
line == curFrame->begin_lines()) {
// Only add text-indent if it has no percentages; using a
// percentage basis of 0 unconditionally would give strange
// behavior for calc(10%-3px).
const nsStyleCoord &indent = GetStyleText()->mTextIndent;
if (indent.GetUnit() == eStyleUnit_Coord)
data.currentLine += indent.GetCoordValue();
if (indent.ConvertsToLength())
data.currentLine += nsRuleNode::ComputeCoordPercentCalc(indent, 0);
}
// XXX Bug NNNNNN Should probably handle percentage text-indent.
@ -5944,19 +5950,17 @@ nsBlockFrame::AdjustForTextIndent(const nsLineBox* aLine,
if (!GetPrevContinuation() && aLine == begin_lines().get()) {
// Adjust for the text-indent. See similar code in
// nsLineLayout::BeginLineReflow.
nscoord indent = 0;
const nsStyleText* styleText = GetStyleText();
nsStyleUnit unit = styleText->mTextIndent.GetUnit();
if (eStyleUnit_Coord == unit) {
indent = styleText->mTextIndent.GetCoordValue();
} else if (eStyleUnit_Percent == unit) {
const nsStyleCoord &textIndent = GetStyleText()->mTextIndent;
nscoord pctBasis = 0;
if (textIndent.HasPercent()) {
// Only work out the percentage basis if we need to.
// It's a percentage of the containing block width.
nsIFrame* containingBlock =
nsHTMLReflowState::GetContainingBlockFor(this);
NS_ASSERTION(containingBlock, "Must have containing block!");
indent = nscoord(styleText->mTextIndent.GetPercentValue() *
containingBlock->GetContentRect().width);
pctBasis = containingBlock->GetContentRect().width;
}
nscoord indent = nsRuleNode::ComputeCoordPercentCalc(textIndent, pctBasis);
// Adjust the start position and the width of the decoration by the
// value of the indent. Note that indent can be negative; that's OK.

Просмотреть файл

@ -231,21 +231,17 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
// property amounts to anything.
if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowState->frame)) {
nscoord indent = 0;
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
if (eStyleUnit_Coord == unit) {
indent = mStyleText->mTextIndent.GetCoordValue();
}
else if (eStyleUnit_Percent == unit) {
nscoord width =
const nsStyleCoord &textIndent = mStyleText->mTextIndent;
nscoord pctBasis = 0;
if (textIndent.HasPercent()) {
pctBasis =
nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState);
if ((0 != width) && (NS_UNCONSTRAINEDSIZE != width)) {
indent = nscoord(mStyleText->mTextIndent.GetPercentValue() * width);
}
if (GetFlag(LL_GOTLINEBOX)) {
mLineBox->DisableResizeReflowOptimization();
}
}
nscoord indent = nsRuleNode::ComputeCoordPercentCalc(textIndent, pctBasis);
mTextIndent = indent;
@ -1783,62 +1779,57 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
}
// Get vertical-align property
const nsStyleTextReset* textStyle = frame->GetStyleTextReset();
nsStyleUnit verticalAlignUnit = textStyle->mVerticalAlign.GetUnit();
const nsStyleCoord& verticalAlign =
frame->GetStyleTextReset()->mVerticalAlign;
#ifdef NOISY_VERTICAL_ALIGN
printf(" [frame]");
nsFrame::ListTag(stdout, frame);
printf(": verticalAlignUnit=%d (enum == %d)\n",
verticalAlignUnit,
((eStyleUnit_Enumerated == verticalAlignUnit)
? textStyle->mVerticalAlign.GetIntValue()
((eStyleUnit_Enumerated == verticalAlign.GetUnit())
? verticalAlign.GetIntValue()
: -1));
#endif
PRUint8 verticalAlignEnum;
nscoord parentAscent, parentDescent, parentXHeight;
nscoord parentSuperscript, parentSubscript;
nscoord coordOffset, percentOffset, elementLineHeight;
nscoord revisedBaselineY;
switch (verticalAlignUnit) {
case eStyleUnit_Enumerated:
default:
if (eStyleUnit_Enumerated == verticalAlignUnit) {
verticalAlignEnum = textStyle->mVerticalAlign.GetIntValue();
}
else {
verticalAlignEnum = NS_STYLE_VERTICAL_ALIGN_BASELINE;
}
switch (verticalAlignEnum) {
if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
switch (verticalAlign.GetIntValue()) {
default:
case NS_STYLE_VERTICAL_ALIGN_BASELINE:
// The elements baseline is aligned with the baseline of
{
// The element's baseline is aligned with the baseline of
// the parent.
pfd->mBounds.y = baselineY - pfd->mAscent;
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_SUB:
{
// Lower the baseline of the box to the subscript offset
// of the parent's box. This is identical to the baseline
// alignment except for the addition of the subscript
// offset to the baseline Y.
nscoord parentSubscript;
fm->GetSubscriptOffset(parentSubscript);
revisedBaselineY = baselineY + parentSubscript;
nscoord revisedBaselineY = baselineY + parentSubscript;
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_SUPER:
{
// Raise the baseline of the box to the superscript offset
// of the parent's box. This is identical to the baseline
// alignment except for the subtraction of the superscript
// offset to the baseline Y.
nscoord parentSuperscript;
fm->GetSuperscriptOffset(parentSuperscript);
revisedBaselineY = baselineY - parentSuperscript;
nscoord revisedBaselineY = baselineY - parentSuperscript;
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_TOP:
{
@ -1871,8 +1862,10 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
}
case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
{
// Align the midpoint of the frame with 1/2 the parents
// x-height above the baseline.
nscoord parentXHeight;
fm->GetXHeight(parentXHeight);
if (frameSpan) {
pfd->mBounds.y = baselineY -
@ -1884,10 +1877,13 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
}
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_TEXT_TOP:
{
// The top of the logical box is aligned with the top of
// the parent elements text.
// the parent element's text.
nscoord parentAscent;
fm->GetMaxAscent(parentAscent);
if (frameSpan) {
pfd->mBounds.y = baselineY - parentAscent -
@ -1898,10 +1894,13 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
}
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM:
{
// The bottom of the logical box is aligned with the
// bottom of the parent elements text.
nscoord parentDescent;
fm->GetMaxDescent(parentDescent);
if (frameSpan) {
pfd->mBounds.y = baselineY + parentDescent -
@ -1914,8 +1913,10 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
}
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
case NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE:
{
// Align the midpoint of the frame with the baseline of the parent.
if (frameSpan) {
pfd->mBounds.y = baselineY - pfd->mBounds.height/2;
@ -1926,33 +1927,26 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
break;
case eStyleUnit_Coord:
}
} else {
// We have either a coord, a percent, or a calc().
nscoord pctBasis = 0;
if (verticalAlign.HasPercent()) {
// Percentages are like lengths, except treated as a percentage
// of the elements line-height value.
pctBasis = nsHTMLReflowState::CalcLineHeight(
frame->GetStyleContext(), mBlockReflowState->ComputedHeight());
}
nscoord offset =
nsRuleNode::ComputeCoordPercentCalc(verticalAlign, pctBasis);
// According to the CSS2 spec (10.8.1), a positive value
// "raises" the box by the given distance while a negative value
// "lowers" the box by the given distance (with zero being the
// baseline). Since Y coordinates increase towards the bottom of
// the screen we reverse the sign.
coordOffset = textStyle->mVerticalAlign.GetCoordValue();
revisedBaselineY = baselineY - coordOffset;
nscoord revisedBaselineY = baselineY - offset;
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
pfd->mVerticalAlign = VALIGN_OTHER;
break;
case eStyleUnit_Percent:
// Similar to a length value (eStyleUnit_Coord) except that the
// percentage is a function of the elements line-height value.
elementLineHeight = nsHTMLReflowState::
CalcLineHeight(frame->GetStyleContext(),
mBlockReflowState->ComputedHeight());
percentOffset = nscoord(
textStyle->mVerticalAlign.GetPercentValue() * elementLineHeight
);
revisedBaselineY = baselineY - percentOffset;
pfd->mBounds.y = revisedBaselineY - pfd->mAscent;
pfd->mVerticalAlign = VALIGN_OTHER;
break;
}
// Update minY/maxY for frames that we just placed. Do not factor

Просмотреть файл

@ -16,6 +16,9 @@
== offsets-relative-right-1.html offsets-relative-left-1-ref.html
== offsets-relative-top-1.html offsets-relative-top-1-ref.html
== padding-block-1.html padding-block-1-ref.html
== text-indent-1.html text-indent-1-ref.html
== text-indent-intrinsic-1.html text-indent-intrinsic-1-ref.html
== vertical-align-1.html vertical-align-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

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<title>text-indent: calc()</title>
<style>
body { width: 500px }
p { font-size: 10px }
</style>
<p style="text-indent: 247px">50% - 3px</p>
<p style="text-indent: 247px">25% - 3px + 25%</p>
<p style="text-indent: 247px">25% - 3px + 12.5% * 2</p>
<p style="text-indent: 247px">25% - 3px + 12.5%*2</p>
<p style="text-indent: 247px">25% - 3px + 2*12.5%</p>
<p style="text-indent: 247px">25% - 3px + 2 * 12.5%</p>
<p style="text-indent: 125px">min(25%, 150px)</p>
<p style="text-indent: 100px">min(25%, 100px)</p>
<p style="text-indent: 150px">max(25%, 150px)</p>
<p style="text-indent: 125px">max(25%, 100px)</p>
<p style="text-indent: 150px">min(25%, 150px) + 5%</p>
<p style="text-indent: 125px">min(25%, 100px) + 5%</p>
<p style="text-indent: 175px">max(25%, 150px) + 5%</p>
<p style="text-indent: 150px">max(25%, 100px) + 5%</p>
<p style="text-indent: 105px">min(25%, 150px) - 2em</p>
<p style="text-indent: 80px">min(25%, 100px) - 2em</p>
<p style="text-indent: 130px">max(25%, 150px) - 2em</p>
<p style="text-indent: 105px">max(25%, 100px) - 2em</p>
<p style="text-indent: 250px">30% + 20%</p>
<p style="text-indent: 250px">30% + max(20%, 1px)</p>
<p style="text-indent: 250px">max(25%, 50%)</p>
<p style="text-indent: 125px">max(25%, 50%)</p>

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Test for vertical-align:calc()</title>
<div style="line-height: 100px; margin-top: 100px">
<span>x</span>
<span style="vertical-align: 50px">x</span>
<span style="vertical-align: 50px">x</span>
<span style="vertical-align: 75px">x</span>
<span style="vertical-align: 45px">x</span>
<span style="vertical-align: 40px">x</span>
<span style="vertical-align: 30px">x</span>
</div>

Просмотреть файл

@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<title>Test for vertical-align:calc()</title>
<div style="line-height: 100px; margin-top: 100px">
<span>x</span>
<span style="vertical-align: -moz-calc(50px)">x</span>
<span style="vertical-align: -moz-calc(50%)">x</span>
<span style="vertical-align: -moz-calc(25px + 50%)">x</span>
<span style="vertical-align: -moz-calc(150% / 2 - 30px)">x</span>
<span style="vertical-align: -moz-calc(40px + 10% - 20% / 2)">x</span>
<span style="vertical-align: -moz-calc(40px - 10%)">x</span>
</div>

Просмотреть файл

@ -5939,7 +5939,7 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
case eCSSProperty_text_decoration:
return ParseTextDecoration(aValue);
case eCSSProperty_text_indent:
return ParseVariant(aValue, VARIANT_HLP, nsnull);
return ParseVariant(aValue, VARIANT_HLP | VARIANT_CALC, nsnull);
case eCSSProperty_text_transform:
return ParseVariant(aValue, VARIANT_HK,
nsCSSProps::kTextTransformKTable);
@ -5959,7 +5959,7 @@ CSSParserImpl::ParseSingleValueProperty(nsCSSValue& aValue,
return ParseVariant(aValue, VARIANT_HK,
nsCSSProps::kUserSelectKTable);
case eCSSProperty_vertical_align:
return ParseVariant(aValue, VARIANT_HKLP,
return ParseVariant(aValue, VARIANT_HKLP | VARIANT_CALC,
nsCSSProps::kVerticalAlignKTable);
case eCSSProperty_visibility:
return ParseVariant(aValue, VARIANT_HK,

Просмотреть файл

@ -3590,10 +3590,10 @@ nsRuleNode::ComputeTextData(void* aStartStruct,
NS_STYLE_TEXT_ALIGN_DEFAULT,
0, 0, 0, 0);
// text-indent: length, percent, inherit, initial
// text-indent: length, percent, calc, inherit, initial
SetCoord(textData.mTextIndent, text->mTextIndent, parentText->mTextIndent,
SETCOORD_LPH | SETCOORD_INITIAL_ZERO, aContext,
mPresContext, canStoreInRuleTree);
SETCOORD_LPH | SETCOORD_INITIAL_ZERO | SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree);
// text-transform: enum, inherit, initial
SetDiscrete(textData.mTextTransform, text->mTextTransform, canStoreInRuleTree,
@ -3643,9 +3643,10 @@ nsRuleNode::ComputeTextResetData(void* aStartStruct,
{
COMPUTE_START_RESET(TextReset, (), text, parentText, Text, textData)
// vertical-align: enum, length, percent, inherit
// vertical-align: enum, length, percent, calc, inherit
if (!SetCoord(textData.mVerticalAlign, text->mVerticalAlign,
parentText->mVerticalAlign, SETCOORD_LPH | SETCOORD_ENUMERATED,
parentText->mVerticalAlign,
SETCOORD_LPH | SETCOORD_ENUMERATED | SETCOORD_STORE_CALC,
aContext, mPresContext, canStoreInRuleTree)) {
if (eCSSUnit_Initial == textData.mVerticalAlign.GetUnit()) {
text->mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE,

Просмотреть файл

@ -1151,7 +1151,7 @@ struct nsStyleTextReset {
PRUint8 mTextDecoration; // [reset] see nsStyleConsts.h
PRUint8 mUnicodeBidi; // [reset] see nsStyleConsts.h
nsStyleCoord mVerticalAlign; // [reset] coord, percent, enum (see nsStyleConsts.h)
nsStyleCoord mVerticalAlign; // [reset] coord, percent, calc, enum (see nsStyleConsts.h)
};
struct nsStyleText {
@ -1181,7 +1181,7 @@ struct nsStyleText {
nsStyleCoord mLetterSpacing; // [inherited] coord, normal
nsStyleCoord mLineHeight; // [inherited] coord, factor, normal
nsStyleCoord mTextIndent; // [inherited] coord, percent
nsStyleCoord mTextIndent; // [inherited] coord, percent, calc
nscoord mWordSpacing; // [inherited]
nsRefPtr<nsCSSShadowArray> mTextShadow; // [inherited] NULL in case of a zero-length

Просмотреть файл

@ -2292,7 +2292,14 @@ var gCSSProperties = {
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "0" ],
other_values: [ "2em", "5%", "-10px" ],
other_values: [ "2em", "5%", "-10px",
"-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: []
},
"text-shadow": {
@ -2396,7 +2403,14 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "baseline" ],
other_values: [ "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom", "15%", "3px", "0.2em", "-5px", "-3%" ],
other_values: [ "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom", "15%", "3px", "0.2em", "-5px", "-3%",
"-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: []
},
"visibility": {