Bug 1470176 - Implement contain:size for fieldset objects. draft
authorMorgan Rae Reschenberg <mreschenberg@mozilla.com>
Tue, 17 Jul 2018 13:14:39 -0700
changeset 822784 2f29e5e770e8879552bcf1a7237b563f02016954
parent 820804 4f12d77b4f9b6adaf06615c1c8cdc14de836dc1a
push id117468
push userbmo:mreschenberg@berkeley.edu
push dateWed, 25 Jul 2018 22:26:30 +0000
bugs1470176
milestone63.0a1
Bug 1470176 - Implement contain:size for fieldset objects. MozReview-Commit-ID: ImkclemDA9o
layout/forms/nsFieldSetFrame.cpp
layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-001-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-001.html
layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-002-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-fieldset-002.html
layout/reftests/w3c-css/submitted/contain/reftest.list
--- 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