Bug 957915 - Handle calc(%) on tables. r=mats
This patch makes us handle calc with percentages when we can convert to percentages the same way we handle plain percentages in table layout. We still treat length + percentage as auto (this matches Blink / WebKit as well). There's one case we differ with Blink / WebKit, which is calc(% + 0px), which they'd treat as auto instead of a percentage. I think this is a bug on them (or at least worth some spec clarification). I filed https://github.com/w3c/csswg-drafts/issues/3482 for that. In practice what that'd means for us if the WG decides that Blink / WebKit is right in that case is that we'd need to keep track of whether the calc() specifies lengths, and return false from ConvertsToPercent if so. In any case, nothing that would massively change this patch, and I think enough of an edge case that is not worth blocking on the CSSWG decision here. Though I could be convinced otherwise of course. Differential Revision: https://phabricator.services.mozilla.com/D15719
This commit is contained in:
@@ -14,6 +14,11 @@
|
||||
<td>x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: 50%">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td>x</td>
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
<td style="width: calc(500px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50% + 1px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50%)">x</td>
|
||||
|
||||
@@ -19,6 +19,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
|
||||
<td>x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: 50%">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td>x</td>
|
||||
|
||||
@@ -16,6 +16,11 @@ table { table-layout: fixed; width: 500px; border-spacing: 0 }
|
||||
<td style="width: calc(500px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50% + 1px)">x</td>
|
||||
<td style="width: 100px">y</td>
|
||||
</table>
|
||||
<table border>
|
||||
<tr>
|
||||
<td style="width: calc(50%)">x</td>
|
||||
|
||||
@@ -172,6 +172,30 @@ class nsStyleCoord {
|
||||
return mUnit == eStyleUnit_Percent || (IsCalcUnit() && CalcHasPercent());
|
||||
}
|
||||
|
||||
static bool ConvertsToPercent(const nsStyleUnit aUnit,
|
||||
const nsStyleUnion aValue) {
|
||||
|
||||
if (aUnit == eStyleUnit_Percent) {
|
||||
return true;
|
||||
}
|
||||
if (!IsCalcUnit(aUnit)) {
|
||||
return false;
|
||||
}
|
||||
auto* calc = AsCalcValue(aValue);
|
||||
return calc->mLength == 0 && calc->mHasPercent;
|
||||
}
|
||||
|
||||
bool ConvertsToPercent() const { return ConvertsToPercent(mUnit, mValue); }
|
||||
|
||||
float ToPercent() const {
|
||||
MOZ_ASSERT(ConvertsToPercent());
|
||||
if (IsCalcUnit()) {
|
||||
MOZ_ASSERT(CalcHasPercent() && GetCalcValue()->mLength == 0);
|
||||
return GetCalcValue()->mPercent;
|
||||
}
|
||||
return mValue.mFloat;
|
||||
}
|
||||
|
||||
static bool ConvertsToLength(const nsStyleUnit aUnit,
|
||||
const nsStyleUnion aValue) {
|
||||
return aUnit == eStyleUnit_Coord ||
|
||||
|
||||
@@ -123,9 +123,9 @@ static CellISizeInfo GetISizeInfo(gfxContext *aRenderingContext,
|
||||
|
||||
const nsStyleCoord &iSize = stylePos->ISize(aWM);
|
||||
nsStyleUnit unit = iSize.GetUnit();
|
||||
// NOTE: We're ignoring calc() units with percentages here, for lack of a
|
||||
// sensible idea for what to do with them. This means calc() with
|
||||
// percentages is basically handled like 'auto' for table cells and
|
||||
// NOTE: We're ignoring calc() units with both lengths and percentages here,
|
||||
// for lack of a sensible idea for what to do with them. This means calc()
|
||||
// with percentages is basically handled like 'auto' for table cells and
|
||||
// columns.
|
||||
if (iSize.ConvertsToLength()) {
|
||||
hasSpecifiedISize = true;
|
||||
@@ -145,8 +145,8 @@ static CellISizeInfo GetISizeInfo(gfxContext *aRenderingContext,
|
||||
minCoord = c;
|
||||
}
|
||||
prefCoord = std::max(c, minCoord);
|
||||
} else if (unit == eStyleUnit_Percent) {
|
||||
prefPercent = iSize.GetPercentValue();
|
||||
} else if (iSize.ConvertsToPercent()) {
|
||||
prefPercent = iSize.ToPercent();
|
||||
} else if (unit == eStyleUnit_Enumerated && aIsCell) {
|
||||
switch (iSize.GetIntValue()) {
|
||||
case NS_STYLE_WIDTH_MAX_CONTENT:
|
||||
@@ -181,13 +181,12 @@ static CellISizeInfo GetISizeInfo(gfxContext *aRenderingContext,
|
||||
nscoord c = aFrame->ComputeISizeValue(aRenderingContext, 0, 0, 0, maxISize);
|
||||
minCoord = std::min(c, minCoord);
|
||||
prefCoord = std::min(c, prefCoord);
|
||||
} else if (unit == eStyleUnit_Percent) {
|
||||
float p = stylePos->MaxISize(aWM).GetPercentValue();
|
||||
} else if (maxISize.ConvertsToPercent()) {
|
||||
float p = maxISize.ToPercent();
|
||||
if (p < prefPercent) {
|
||||
prefPercent = p;
|
||||
}
|
||||
}
|
||||
// treat calc() with percentages on max-inline-size just like 'none'.
|
||||
|
||||
nsStyleCoord minISize(stylePos->MinISize(aWM));
|
||||
if (minISize.GetUnit() == eStyleUnit_Enumerated) {
|
||||
@@ -203,13 +202,12 @@ static CellISizeInfo GetISizeInfo(gfxContext *aRenderingContext,
|
||||
nscoord c = aFrame->ComputeISizeValue(aRenderingContext, 0, 0, 0, minISize);
|
||||
minCoord = std::max(c, minCoord);
|
||||
prefCoord = std::max(c, prefCoord);
|
||||
} else if (unit == eStyleUnit_Percent) {
|
||||
float p = stylePos->MinISize(aWM).GetPercentValue();
|
||||
} else if (minISize.ConvertsToPercent()) {
|
||||
float p = minISize.ToPercent();
|
||||
if (p > prefPercent) {
|
||||
prefPercent = p;
|
||||
}
|
||||
}
|
||||
// treat calc() with percentages on min-inline-size just like '0'.
|
||||
|
||||
// XXX Should col frame have border/padding considered?
|
||||
if (aIsCell) {
|
||||
|
||||
@@ -71,13 +71,13 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() {}
|
||||
if (styleISize->ConvertsToLength()) {
|
||||
result +=
|
||||
colFrame->ComputeISizeValue(aRenderingContext, 0, 0, 0, *styleISize);
|
||||
} else if (styleISize->GetUnit() == eStyleUnit_Percent) {
|
||||
} else if (styleISize->ConvertsToPercent()) {
|
||||
// do nothing
|
||||
} else {
|
||||
NS_ASSERTION(
|
||||
styleISize->GetUnit() == eStyleUnit_Auto ||
|
||||
styleISize->GetUnit() == eStyleUnit_Enumerated ||
|
||||
(styleISize->IsCalcUnit() && styleISize->CalcHasPercent()),
|
||||
(styleISize->IsCalcUnit() && !styleISize->ConvertsToPercent()),
|
||||
"bad inline size");
|
||||
|
||||
// The 'table-layout: fixed' algorithm considers only cells in the
|
||||
@@ -102,14 +102,14 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() {}
|
||||
cellISize = ((cellISize + spacing) / colSpan) - spacing;
|
||||
}
|
||||
result += cellISize;
|
||||
} else if (styleISize->GetUnit() == eStyleUnit_Percent) {
|
||||
} else if (styleISize->ConvertsToPercent()) {
|
||||
if (colSpan > 1) {
|
||||
// XXX Can this force columns to negative inline sizes?
|
||||
result -= spacing * (colSpan - 1);
|
||||
}
|
||||
}
|
||||
// else, for 'auto', '-moz-available', '-moz-fit-content',
|
||||
// and 'calc()' with percentages, do nothing
|
||||
// and 'calc()' with both lengths and percentages, do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,8 +209,8 @@ static inline nscoord AllocateUnassigned(nscoord aUnassignedSpace,
|
||||
colISize = colFrame->ComputeISizeValue(aReflowInput.mRenderingContext, 0,
|
||||
0, 0, *styleISize);
|
||||
specTotal += colISize;
|
||||
} else if (styleISize->GetUnit() == eStyleUnit_Percent) {
|
||||
float pct = styleISize->GetPercentValue();
|
||||
} else if (styleISize->ConvertsToPercent()) {
|
||||
float pct = styleISize->ToPercent();
|
||||
colISize = NSToCoordFloor(pct * float(tableISize));
|
||||
colFrame->AddPrefPercent(pct);
|
||||
pctTotal += pct;
|
||||
@@ -218,7 +218,7 @@ static inline nscoord AllocateUnassigned(nscoord aUnassignedSpace,
|
||||
NS_ASSERTION(
|
||||
styleISize->GetUnit() == eStyleUnit_Auto ||
|
||||
styleISize->GetUnit() == eStyleUnit_Enumerated ||
|
||||
(styleISize->IsCalcUnit() && styleISize->CalcHasPercent()),
|
||||
(styleISize->IsCalcUnit() && !styleISize->ConvertsToPercent()),
|
||||
"bad inline size");
|
||||
|
||||
// The 'table-layout: fixed' algorithm considers only cells in the
|
||||
@@ -242,9 +242,9 @@ static inline nscoord AllocateUnassigned(nscoord aUnassignedSpace,
|
||||
colISize = nsLayoutUtils::IntrinsicForContainer(
|
||||
aReflowInput.mRenderingContext, cellFrame,
|
||||
nsLayoutUtils::MIN_ISIZE);
|
||||
} else if (styleISize->GetUnit() == eStyleUnit_Percent) {
|
||||
} else if (styleISize->ConvertsToPercent()) {
|
||||
// XXX This should use real percentage padding
|
||||
float pct = styleISize->GetPercentValue();
|
||||
float pct = styleISize->ToPercent();
|
||||
colISize = NSToCoordFloor(pct * float(tableISize));
|
||||
|
||||
if (cellStylePos->mBoxSizing == StyleBoxSizing::Content) {
|
||||
@@ -273,7 +273,7 @@ static inline nscoord AllocateUnassigned(nscoord aUnassignedSpace,
|
||||
colISize = 0;
|
||||
}
|
||||
}
|
||||
if (styleISize->GetUnit() != eStyleUnit_Percent) {
|
||||
if (!styleISize->ConvertsToPercent()) {
|
||||
specTotal += colISize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,10 +503,9 @@ nscoord nsTableRowFrame::CalcBSize(const ReflowInput& aReflowInput) {
|
||||
const nsStyleCoord& bsizeStyleCoord = position->BSize(wm);
|
||||
if (bsizeStyleCoord.ConvertsToLength()) {
|
||||
SetFixedBSize(bsizeStyleCoord.ComputeCoordPercentCalc(0));
|
||||
} else if (eStyleUnit_Percent == bsizeStyleCoord.GetUnit()) {
|
||||
SetPctBSize(bsizeStyleCoord.GetPercentValue());
|
||||
} else if (bsizeStyleCoord.ConvertsToPercent()) {
|
||||
SetPctBSize(bsizeStyleCoord.ToPercent());
|
||||
}
|
||||
// calc() with percentages is treated like 'auto' on table rows.
|
||||
|
||||
for (nsIFrame* kidFrame : mFrames) {
|
||||
nsTableCellFrame* cellFrame = do_QueryFrame(kidFrame);
|
||||
@@ -569,44 +568,26 @@ nsresult nsTableRowFrame::CalculateCellActualBSize(nsTableCellFrame* aCellFrame,
|
||||
int32_t rowSpan = GetTableFrame()->GetEffectiveRowSpan(*aCellFrame);
|
||||
|
||||
const nsStyleCoord& bsizeStyleCoord = position->BSize(aWM);
|
||||
switch (bsizeStyleCoord.GetUnit()) {
|
||||
case eStyleUnit_Calc: {
|
||||
if (bsizeStyleCoord.CalcHasPercent()) {
|
||||
// Treat this like "auto"
|
||||
break;
|
||||
}
|
||||
// Fall through to the coord case
|
||||
MOZ_FALLTHROUGH;
|
||||
if (bsizeStyleCoord.ConvertsToLength()) {
|
||||
// In quirks mode, table cell isize should be content-box, but bsize
|
||||
// should be border-box.
|
||||
// Because of this historic anomaly, we do not use quirk.css
|
||||
// (since we can't specify one value of box-sizing for isize and another
|
||||
// for bsize)
|
||||
specifiedBSize = bsizeStyleCoord.ToLength();
|
||||
if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks &&
|
||||
position->mBoxSizing == StyleBoxSizing::Content) {
|
||||
specifiedBSize +=
|
||||
aCellFrame->GetLogicalUsedBorderAndPadding(aWM).BStartEnd(aWM);
|
||||
}
|
||||
case eStyleUnit_Coord: {
|
||||
// In quirks mode, table cell isize should be content-box, but bsize
|
||||
// should be border-box.
|
||||
// Because of this historic anomaly, we do not use quirk.css
|
||||
// (since we can't specify one value of box-sizing for isize and another
|
||||
// for bsize)
|
||||
specifiedBSize = bsizeStyleCoord.ComputeCoordPercentCalc(0);
|
||||
if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks &&
|
||||
position->mBoxSizing == StyleBoxSizing::Content) {
|
||||
specifiedBSize +=
|
||||
aCellFrame->GetLogicalUsedBorderAndPadding(aWM).BStartEnd(aWM);
|
||||
}
|
||||
|
||||
if (1 == rowSpan) {
|
||||
SetFixedBSize(specifiedBSize);
|
||||
}
|
||||
break;
|
||||
if (1 == rowSpan) {
|
||||
SetFixedBSize(specifiedBSize);
|
||||
}
|
||||
case eStyleUnit_Percent: {
|
||||
if (1 == rowSpan) {
|
||||
SetPctBSize(bsizeStyleCoord.GetPercentValue());
|
||||
}
|
||||
// pct bsizes are handled when all of the cells are finished,
|
||||
// so don't set specifiedBSize
|
||||
break;
|
||||
} else if (bsizeStyleCoord.ConvertsToPercent()) {
|
||||
if (1 == rowSpan) {
|
||||
SetPctBSize(bsizeStyleCoord.ToPercent());
|
||||
}
|
||||
case eStyleUnit_Auto:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// If the specified bsize is greater than the desired bsize,
|
||||
@@ -1357,8 +1338,8 @@ void nsTableRowFrame::InitHasCellWithStyleBSize(nsTableFrame* aTableFrame) {
|
||||
const nsStyleCoord& cellBSize = cellFrame->StylePosition()->BSize(wm);
|
||||
if (aTableFrame->GetEffectiveRowSpan(*cellFrame) == 1 &&
|
||||
cellBSize.GetUnit() != eStyleUnit_Auto &&
|
||||
/* calc() with percentages treated like 'auto' */
|
||||
(!cellBSize.IsCalcUnit() || !cellBSize.HasPercent())) {
|
||||
/* calc() with both percentages and lengths treated like 'auto' */
|
||||
(cellBSize.ConvertsToLength() || cellBSize.ConvertsToPercent())) {
|
||||
AddStateBits(NS_ROW_HAS_CELL_WITH_STYLE_BSIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[calc-width-table-auto-1.html]
|
||||
expected: FAIL
|
||||
@@ -0,0 +1,2 @@
|
||||
[calc-width-table-fixed-1.html]
|
||||
expected: FAIL
|
||||
Reference in New Issue
Block a user