Bug 1470176 - Implement contain:size for Select. draft
authorMorgan Rae Reschenberg <mreschenberg@mozilla.com>
Wed, 27 Jun 2018 15:46:31 -0700
changeset 818970 d54142228e7b3cd54ba88a7bd6b102e169f4c8d8
parent 818682 2ed1506d1dc7db3d70a3feed95f1456bce05bbee
push id116412
push userbmo:mreschenberg@berkeley.edu
push dateMon, 16 Jul 2018 22:37:39 +0000
bugs1470176
milestone63.0a1
Bug 1470176 - Implement contain:size for Select. MozReview-Commit-ID: JPD1BInDeT0
layout/forms/nsComboboxControlFrame.cpp
layout/forms/nsListControlFrame.cpp
layout/generic/nsBlockFrame.cpp
layout/reftests/w3c-css/submitted/contain/contain-size-select-001-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-select-001.html
layout/reftests/w3c-css/submitted/contain/contain-size-select-002-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-select-002.html
layout/reftests/w3c-css/submitted/contain/reftest.list
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -819,26 +819,42 @@ nsComboboxControlFrame::GetIntrinsicISiz
 
 }
 
 nscoord
 nsComboboxControlFrame::GetMinISize(gfxContext *aRenderingContext)
 {
   nscoord minISize;
   DISPLAY_MIN_WIDTH(this, minISize);
-  minISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE);
+  if (StyleDisplay()->IsContainSize()) {
+    // XXX We probably want to modify GetIntrinsicISize, or
+    // the subsequent call to nsBlockFrame::GetPrefISize,
+    // to take into account the default size of an empty
+    // select object (which is nonzero). See bug 1476127.
+    minISize = 0;
+  } else {
+    minISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::MIN_ISIZE);
+  }
   return minISize;
 }
 
 nscoord
 nsComboboxControlFrame::GetPrefISize(gfxContext *aRenderingContext)
 {
   nscoord prefISize;
   DISPLAY_PREF_WIDTH(this, prefISize);
-  prefISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE);
+  if (StyleDisplay()->IsContainSize()) {
+    // XXX We probably want to modify GetIntrinsicISize, or
+    // the subsequent call to nsBlockFrame::GetPrefISize,
+    // to take into account the default size of an empty
+    // select object (which is nonzero). See bug 1476127.
+    prefISize = 0;
+  } else {
+    prefISize = GetIntrinsicISize(aRenderingContext, nsLayoutUtils::PREF_ISIZE);
+  }
   return prefISize;
 }
 
 void
 nsComboboxControlFrame::Reflow(nsPresContext*          aPresContext,
                                ReflowOutput&     aDesiredSize,
                                const ReflowInput& aReflowInput,
                                nsReflowStatus&          aStatus)
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -310,19 +310,20 @@ nsListControlFrame::CalcBSizeOfARow()
   // Calculate the block size in our writing mode of a single row in the
   // listbox or dropdown list by using the tallest thing in the subtree,
   // since there may be option groups in addition to option elements,
   // either of which may be visible or invisible, may use different
   // fonts, etc.
   int32_t blockSizeOfARow = GetMaxOptionBSize(GetOptionsContainer(),
                                               GetWritingMode());
 
-  // Check to see if we have zero items (and optimize by checking
-  // blockSizeOfARow first)
-  if (blockSizeOfARow == 0 && GetNumberOfOptions() == 0) {
+  // Check to see if we have zero items or are size contained
+  // (and optimize by checking blockSizeOfARow first)
+  if ((blockSizeOfARow == 0 && GetNumberOfOptions() == 0) ||
+      StyleDisplay()->IsContainSize()) {
     float inflation = nsLayoutUtils::FontSizeInflationFor(this);
     blockSizeOfARow = CalcFallbackRowBSize(inflation);
   }
 
   return blockSizeOfARow;
 }
 
 nscoord
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -484,17 +484,17 @@ bool
 nsBlockFrame::GetNaturalBaselineBOffset(mozilla::WritingMode aWM,
                                         BaselineSharingGroup aBaselineGroup,
                                         nscoord*             aBaseline) const
 {
   if (aBaselineGroup == BaselineSharingGroup::eFirst) {
     return nsLayoutUtils::GetFirstLineBaseline(aWM, this, aBaseline);
   }
 
-  if (StyleDisplay()->IsContainSize()) {
+  if (StyleDisplay()->IsContainSize() && !IsComboboxControlFrame()) {
     return false;
   }
 
   for (ConstReverseLineIterator line = LinesRBegin(), line_end = LinesREnd();
        line != line_end; ++line) {
     if (line->IsBlock()) {
       nscoord offset;
       nsIFrame* kid = line->mFirstChild;
@@ -1632,21 +1632,23 @@ nsBlockFrame::ComputeFinalSize(const Ref
       // on its own on the last-in-flow, even if we ran out of height
       // here. We need GetSkipSides to check whether we ran out of content
       // height in the current frame, not whether it's last-in-flow.
     }
 
     // Don't carry out a block-end margin when our BSize is fixed.
     aMetrics.mCarriedOutBEndMargin.Zero();
   }
-  else if (aReflowInput.mStyleDisplay->IsContainSize()) {
+  else if (aReflowInput.mStyleDisplay->IsContainSize() && !IsComboboxControlFrame()) {
     // If we're size-containing and we don't have a specified size, then our
     // final size should actually be computed from only our border and padding,
     // as though we were empty.
     // Hence this case is a simplified version of the case below.
+    // We want to avoid resizing comboboxes (which call this reflow method)
+    // because we handle resizing elsewhere in their class.
     nscoord contentBSize = 0;
     nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
     aMetrics.mCarriedOutBEndMargin.Zero();
     autoBSize += borderPadding.BStartEnd(wm);
     finalSize.BSize(wm) = autoBSize;
   }
   else if (aState.mReflowStatus.IsComplete()) {
     nscoord contentBSize = blockEndEdgeOfChildren - borderPadding.BStart(wm);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-select-001-ref.html
@@ -0,0 +1,41 @@
+<!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>
+  .minWidth {
+    min-width: 100px;
+  }
+  .width {
+    width: 100px;
+  }
+  .floatLWidth {
+    float: left;
+    width: 100px;
+  }
+  .iFlexWidth {
+    display: inline-flex;
+    width: 100px;
+  }
+  </style>
+</head>
+<body>
+  <select class="floatLWidth">
+  </select>
+  <br style="clear:both;">
+
+
+  <select class="iFlexWidth">
+  </select>
+  <br>
+
+  <select class="minWidth">
+  </select>
+  <br>
+
+  <select class="width">
+  </select>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-select-001.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Test: 'contain: size' on select objects should cause them to behave as if they have no contents.</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="match" href="contain-size-select-001-ref.html">
+  <style>
+  select {
+    contain: size;
+    color: transparent;
+  }
+  .minWidth {
+    min-width: 100px;
+  }
+  .width {
+    width: 100px;
+  }
+  .floatLWidth {
+    float: left;
+    width: 100px;
+  }
+  .iFlexWidth {
+    display: inline-flex;
+    width: 100px;
+  }
+  </style>
+</head>
+<body>
+  <select class="floatLWidth">
+    <option>CSS Test: A size-contained floated select with specified width and no specified height should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br style="clear:both;">
+
+  <select class="iFlexWidth">
+    <option>CSS Test: A size-contained inline-flex select with specified width and no specified height should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+  <select class="minWidth">
+    <option>CSS Test: A size-contained select with specified min-width should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+  <select class="width">
+    <option>CSS Test: A size-contained select with specified width should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-select-002-ref.html
@@ -0,0 +1,32 @@
+<!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>
+  .floatLBasic {
+    float: left;
+  }
+  .iFlexBasic {
+    display: inline-flex;
+  }
+  </style>
+</head>
+<body>
+  <select>
+  </select>
+  <br>
+
+  <select class="floatLBasic">
+  </select>
+  <br style="clear:both;">
+
+  <select class="iFlexBasic">
+  </select>
+  <br>
+
+  outside before<select>
+  </select>outside after
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-select-002.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Test: 'contain: size' on select objects should cause them to behave as if they have no contents.</title>
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <link rel="match" href="contain-size-select-002-ref.html">
+  <style>
+  select {
+    contain: size;
+    color: transparent;
+  }
+  .floatLBasic {
+    float: left;
+  }
+  .iFlexBasic {
+    display: inline-flex;
+  }
+  </style>
+</head>
+<body>
+  <select>
+    <option>CSS Test: A size-contained select with no specified size should render as if it had no contents.</option>
+    <option>aaaaaa</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+
+  <select class="floatLBasic">
+    <option>CSS Test: A size-contained floated select with auto width and no specified height should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br style="clear:both;">
+
+  <select class="iFlexBasic">
+    <option>CSS Test: A size-contained inline-flex select with auto width and no specified height should render as if it had no contents.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>
+  <br>
+
+  outside before<select>
+    <option>CSS Test: A size-contained select should perform baseline alignment as if the container were empty.</option>
+    <option>a</option>
+    <option>b</option>
+    <option>c</option>
+  </select>outside after
+</body>
+</html>
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -18,8 +18,10 @@ 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-select-001.html contain-size-select-001-ref.html
+fails == contain-size-select-002.html contain-size-select-002-ref.html # bug 1476127