Bug 1470176 - Implement contain:size for fieldset objects.
MozReview-Commit-ID: ImkclemDA9o
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -311,28 +311,32 @@ nsFieldSetFrame::PaintBorder(
}
nscoord
nsFieldSetFrame::GetIntrinsicISize(gfxContext* aRenderingContext,
nsLayoutUtils::IntrinsicISizeType aType)
{
nscoord legendWidth = 0;
nscoord contentWidth = 0;
- if (nsIFrame* legend = GetLegend()) {
- legendWidth =
- nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType);
- }
+ if (!StyleDisplay()->IsContainSize()) {
+ // Both inner and legend are children, and if the fieldset is
+ // size-contained they should not contribute to the intrinsic size.
+ if (nsIFrame* legend = GetLegend()) {
+ legendWidth =
+ nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType);
+ }
- if (nsIFrame* inner = GetInner()) {
- // Ignore padding on the inner, since the padding will be applied to the
- // outer instead, and the padding computed for the inner is wrong
- // for percentage padding.
- contentWidth =
- nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType,
- nsLayoutUtils::IGNORE_PADDING);
+ if (nsIFrame* inner = GetInner()) {
+ // Ignore padding on the inner, since the padding will be applied to the
+ // outer instead, and the padding computed for the inner is wrong
+ // for percentage padding.
+ contentWidth =
+ nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType,
+ nsLayoutUtils::IGNORE_PADDING);
+ }
}
return std::max(legendWidth, contentWidth);
}
nscoord
nsFieldSetFrame::GetMinISize(gfxContext* aRenderingContext)
@@ -583,16 +587,31 @@ nsFieldSetFrame::Reflow(nsPresContext*
nsContainerFrame::PositionFrameView(legend);
nsContainerFrame::PositionChildViews(legend);
}
// Return our size and our result.
LogicalSize finalSize(wm, contentRect.ISize(wm) + border.IStartEnd(wm),
mLegendSpace + border.BStartEnd(wm) +
(inner ? inner->BSize(wm) : 0));
+ if (aReflowInput.mStyleDisplay->IsContainSize()) {
+ // If we're size-contained, then we must set finalSize to be what
+ // it'd be if we had no children (i.e. if we had no legend and if
+ // 'inner' were empty). Note: normally the fieldset's own padding
+ // (which we still must honor) would be accounted for as part of
+ // inner's size (see kidReflowInput.Init() call above). So: since
+ // we're disregarding sizing information from 'inner', we need to
+ // account for that padding ourselves here.
+ nscoord contentBoxBSize =
+ aReflowInput.ComputedBSize() == NS_UNCONSTRAINEDSIZE
+ ? aReflowInput.ApplyMinMaxBSize(0)
+ : aReflowInput.ComputedBSize();
+ finalSize.BSize(wm) = contentBoxBSize +
+ aReflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
+ }
aDesiredSize.SetSize(wm, finalSize);
aDesiredSize.SetOverflowAreasToDesiredBounds();
if (legend) {
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend);
}
if (inner) {
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner);
@@ -664,31 +683,41 @@ nsFieldSetFrame::GetLogicalBaseline(Writ
AlignmentContext::eInline);
}
}
bool
nsFieldSetFrame::GetVerticalAlignBaseline(WritingMode aWM,
nscoord* aBaseline) const
{
+ if (StyleDisplay()->IsContainSize()) {
+ // If we are size-contained, our child 'inner' should not
+ // affect how we calculate our baseline.
+ return false;
+ }
nsIFrame* inner = GetInner();
MOZ_ASSERT(!inner->GetWritingMode().IsOrthogonalTo(aWM));
if (!inner->GetVerticalAlignBaseline(aWM, aBaseline)) {
return false;
}
nscoord innerBStart = inner->BStart(aWM, GetSize());
*aBaseline += innerBStart;
return true;
}
bool
nsFieldSetFrame::GetNaturalBaselineBOffset(WritingMode aWM,
BaselineSharingGroup aBaselineGroup,
nscoord* aBaseline) const
{
+ if (StyleDisplay()->IsContainSize()) {
+ // If we are size-contained, our child 'inner' should not
+ // affect how we calculate our baseline.
+ return false;
+ }
nsIFrame* inner = GetInner();
MOZ_ASSERT(!inner->GetWritingMode().IsOrthogonalTo(aWM));
if (!inner->GetNaturalBaselineBOffset(aWM, aBaselineGroup, aBaseline)) {
return false;
}
nscoord innerBStart = inner->BStart(aWM, GetSize());
if (aBaselineGroup == BaselineSharingGroup::eFirst) {
*aBaseline += innerBStart;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-001-ref.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ visibility: hidden;
+ border: none;
+ }
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ }
+ .height {
+ height: 30px;
+ }
+ .width {
+ width: 30px;
+ }
+ </style>
+</head>
+<body>
+ <div class="container"><fieldset class="basic"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic height"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic height"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic width"></fieldset></div>
+ <br>
+
+ <div class="container"><fieldset class="basic width"></fieldset></div>
+ <br>
+
+ <fieldset class="height"><legend>legend</legend></fieldset>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-001.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on fieldset elements should cause them to be sized as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-fieldset-001-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ visibility: hidden;
+ border: none;
+ color: transparent;
+ }
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ }
+ .innerContents {
+ height: 50px;
+ width: 50px;
+ }
+ .minHeight {
+ min-height: 30px;
+ }
+ .height {
+ height: 30px;
+ }
+ .minWidth {
+ min-width: 30px;
+ }
+ .width {
+ width: 30px;
+ }
+ </style>
+</head>
+<body>
+ <!--Note: The following .container class is used to help test if size-contained
+ fieldsets and non-contained fieldsets have the same size. Normally, we'd test
+ that a fieldset with children and size-containment is drawn identically to a
+ fieldset without containment or children. However, when we have a legend as
+ a child, border placement and padding of the fieldset are changed.
+ To check the dimensions between the ref-case and test-case without
+ failing because of the border/padding differences, we make the fieldset
+ {visibility:hidden; border:none;} and add a .container wrapper div.-->
+
+ <!--CSS Test: A size-contained fieldset element with no specified size should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified min-height should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain minHeight">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified height should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain height">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified min-width should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain minWidth">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size-contained fieldset element with specified width should size itself as if it had no contents.-->
+ <div class="container">
+ <fieldset class="contain width">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>
+ </div>
+ <br>
+
+ <!--CSS Test: A size contained fieldset element with a legend should draw its legend and border in the same way as a non-contained fieldset element-->
+ <fieldset class="height" style="contain:size;">
+ <legend>legend</legend>
+ </fieldset>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-002-ref.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Reftest Reference</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <style>
+ .basic {
+ border: none;
+ visibility: hidden;
+ }
+ .container {
+ border: 10px solid green;
+ display: inline-block;
+ }
+ .floatLBasic-ref {
+ float: left;
+ }
+ .floatLWidth-ref {
+ float: left;
+ width: 30px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <div class="flexBaselineCheck">
+ outside before<fieldset class="basic"></fieldset>outside after
+ </div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-002.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Test: 'contain: size' on fieldset elements should cause them to be baseline-aligned as if they had no contents.</title>
+ <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+ <link rel="help" href="https://drafts.csswg.org/css-contain/#containment-size">
+ <link rel="match" href="contain-size-fieldset-002-ref.html">
+ <style>
+ .contain {
+ contain: size;
+ border: none;
+ color: transparent;
+ visibility: hidden;
+ }
+ .innerContents {
+ height: 50px;
+ width: 50px;
+ }
+ .flexBaselineCheck {
+ display: flex;
+ align-items: baseline;
+ }
+ </style>
+</head>
+<body>
+ <!--CSS Test: A size-contained fieldset element should perform baseline alignment as if the container were empty.-->
+ <div class="flexBaselineCheck">
+ outside before<fieldset class="contain">
+ <legend>legend</legend>
+ <div class="innerContents">inner</div>
+ </fieldset>outside after
+ </div>
+</body>
+</html>
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -18,10 +18,12 @@ pref(layout.css.overflow-clip-box.enable
== contain-paint-stacking-context-001a.html contain-paint-stacking-context-001-ref.html
== contain-paint-stacking-context-001b.html contain-paint-stacking-context-001-ref.html
== contain-size-button-001.html contain-size-button-001-ref.html
== contain-size-block-001.html contain-size-block-001-ref.html
== contain-size-inline-block-001.html contain-size-inline-block-001-ref.html
== contain-size-flex-001.html contain-size-flex-001-ref.html
fuzzy-if(webrender&&winWidget,3,2) == contain-size-inline-flex-001.html contain-size-inline-flex-001-ref.html # bug 1474093
== contain-size-multicol-001.html contain-size-multicol-001-ref.html
+== contain-size-fieldset-001.html contain-size-fieldset-001-ref.html
+== contain-size-fieldset-002.html contain-size-fieldset-002-ref.html
== contain-size-multicol-002.html contain-size-multicol-002-ref.html
== contain-size-multicol-003.html contain-size-multicol-003-ref.html