Bug 1467209 - Implement contain:size for HTMLButtonControlFrame. draft
authorMorgan Rae Reschenberg <mreschenberg@mozilla.com>
Fri, 29 Jun 2018 10:27:55 -0700
changeset 815209 ea7479fc2ed7cc25b95702b6c74265a29450e9a7
parent 815208 9849ea3937e2e7c97f79b1d2b601f956181b4629
child 815210 0e41f67e74c6aa759cca728bf871147af54fe360
push id115462
push userbmo:mreschenberg@berkeley.edu
push dateFri, 06 Jul 2018 22:06:52 +0000
bugs1467209
milestone63.0a1
Bug 1467209 - Implement contain:size for HTMLButtonControlFrame. MozReview-Commit-ID: Jsjs3jxy4z3
layout/forms/nsHTMLButtonControlFrame.cpp
layout/reftests/w3c-css/submitted/contain/contain-size-button-001-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-button-001.html
layout/reftests/w3c-css/submitted/contain/reftest.list
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -141,36 +141,40 @@ nsHTMLButtonControlFrame::BuildDisplayLi
   DisplaySelectionOverlay(aBuilder, aLists.Content());
 }
 
 nscoord
 nsHTMLButtonControlFrame::GetMinISize(gfxContext* aRenderingContext)
 {
   nscoord result;
   DISPLAY_MIN_WIDTH(this, result);
-
-  nsIFrame* kid = mFrames.FirstChild();
-  result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
-                                                kid,
-                                                nsLayoutUtils::MIN_ISIZE);
-
+  if (StyleDisplay()->IsContainSize()) {
+    result = 0;
+  } else {
+    nsIFrame* kid = mFrames.FirstChild();
+    result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+                                                  kid,
+                                                  nsLayoutUtils::MIN_ISIZE);
+  }
   return result;
 }
 
 nscoord
 nsHTMLButtonControlFrame::GetPrefISize(gfxContext* aRenderingContext)
 {
   nscoord result;
   DISPLAY_PREF_WIDTH(this, result);
-
-  nsIFrame* kid = mFrames.FirstChild();
-  result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
-                                                kid,
-                                                nsLayoutUtils::PREF_ISIZE);
-
+  if (StyleDisplay()->IsContainSize()) {
+    result = 0;
+  } else {
+    nsIFrame* kid = mFrames.FirstChild();
+    result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
+                                                  kid,
+                                                  nsLayoutUtils::PREF_ISIZE);
+  }
   return result;
 }
 
 void
 nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
                                  ReflowOutput& aDesiredSize,
                                  const ReflowInput& aReflowInput,
                                  nsReflowStatus& aStatus)
@@ -256,16 +260,21 @@ nsHTMLButtonControlFrame::ReflowButtonCo
              "We gave button-contents frame unconstrained available height, "
              "so it should be complete");
 
   // Compute the button's content-box size:
   LogicalSize buttonContentBox(wm);
   if (aButtonReflowInput.ComputedBSize() != NS_INTRINSICSIZE) {
     // Button has a fixed block-size -- that's its content-box bSize.
     buttonContentBox.BSize(wm) = aButtonReflowInput.ComputedBSize();
+  } else if (aButtonReflowInput.mStyleDisplay->IsContainSize()) {
+    // Button is intrinsically sized and has size containment.
+    // It should have a BSize that is either zero or the minimum
+    // specified BSize.
+    buttonContentBox.BSize(wm) = aButtonReflowInput.ComputedMinBSize();
   } else {
     // Button is intrinsically sized -- it should shrinkwrap the
     // button-contents' bSize:
     buttonContentBox.BSize(wm) = contentsDesiredSize.BSize(wm);
 
     // Make sure we obey min/max-bSize in the case when we're doing intrinsic
     // sizing (we get it for free when we have a non-intrinsic
     // aButtonReflowInput.ComputedBSize()).  Note that we do this before
@@ -273,16 +282,18 @@ nsHTMLButtonControlFrame::ReflowButtonCo
     // mComputedMinBSize are content bSizes.
     buttonContentBox.BSize(wm) =
       NS_CSS_MINMAX(buttonContentBox.BSize(wm),
                     aButtonReflowInput.ComputedMinBSize(),
                     aButtonReflowInput.ComputedMaxBSize());
   }
   if (aButtonReflowInput.ComputedISize() != NS_INTRINSICSIZE) {
     buttonContentBox.ISize(wm) = aButtonReflowInput.ComputedISize();
+  } else if (aButtonReflowInput.mStyleDisplay->IsContainSize()) {
+    buttonContentBox.ISize(wm) = aButtonReflowInput.ComputedMinISize();
   } else {
     buttonContentBox.ISize(wm) = contentsDesiredSize.ISize(wm);
     buttonContentBox.ISize(wm) =
       NS_CSS_MINMAX(buttonContentBox.ISize(wm),
                     aButtonReflowInput.ComputedMinISize(),
                     aButtonReflowInput.ComputedMaxISize());
   }
 
@@ -317,17 +328,24 @@ nsHTMLButtonControlFrame::ReflowButtonCo
   aButtonDesiredSize.SetSize(wm,
     LogicalSize(wm, aButtonReflowInput.ComputedISize() + clbp.IStartEnd(wm),
                     buttonContentBox.BSize(wm) + clbp.BStartEnd(wm)));
 
   //  * Button's ascent is its child's ascent, plus the child's block-offset
   // within our frame... unless it's orthogonal, in which case we'll use the
   // contents inline-size as an approximation for now.
   // XXX is there a better strategy? should we include border-padding?
-  if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
+  if (aButtonReflowInput.mStyleDisplay->IsContainSize()) {
+    // If we're size-contained, we should pretend our contents had 0 height
+    // (as they would, if we had no children). This case is identical to the
+    // final else case, but uses only our specified button height for ascent
+    // (ie. it ignores the height returned in contentsDesiredSize).
+    nscoord containAscent = (buttonContentBox.BSize(wm) / 2) + clbp.BStart(wm);
+    aButtonDesiredSize.SetBlockStartAscent(containAscent);
+  } else if (aButtonDesiredSize.GetWritingMode().IsOrthogonalTo(wm)) {
     aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.ISize(wm));
   } else {
     aButtonDesiredSize.SetBlockStartAscent(contentsDesiredSize.BlockStartAscent() +
                                            childPos.B(wm));
   }
 
   aButtonDesiredSize.SetOverflowAreasToDesiredBounds();
 }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-button-001-ref.html
@@ -0,0 +1,73 @@
+<!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>
+  button {
+    border: 1em solid green;
+  }
+  .width-ref {
+    width: 50px;
+  }
+  .height-ref {
+    height: 50px;
+    background: lightblue;
+  }
+  .floatLBasic-ref {
+    float: left;
+  }
+  .floatLWidth-ref {
+    float: left;
+    width: 50px;
+  }
+  .iFlexBasic-ref {
+    display: inline-flex;
+  }
+  .iFlexWidth-ref {
+    display: inline-flex;
+    width: 50px;
+  }
+  .orthog-ref {
+    writing-mode: vertical-lr;
+  }
+  </style>
+</head>
+<body>
+  <button></button>
+  <br>
+
+  <button class="floatLBasic-ref"></button>
+  <br>
+
+  <button class="floatLWidth-ref"></button>
+  <br>
+
+  <button class="iFlexBasic-ref"></button>
+  <br>
+
+  <button class="iFlexWidth-ref"></button>
+  <br>
+
+  outside before<button></button>outside after
+  <br>
+
+  <button class="width-ref"></button>
+  <br>
+
+  <button class="width-ref"></button>
+  <br>
+
+  <button class="height-ref"></button>
+  <br>
+
+  <button class="height-ref"></button>
+  <br>
+
+  s<button class="orthog-ref"></button>endtext
+  <br>
+
+  <button class="height-ref width-ref">inside</button>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-button-001.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Test: 'contain: size' on buttons should cause them to be sized and 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-button-001-ref.html">
+  <style>
+  button {
+    contain: size;
+    border: 1em solid green;
+    background: red;
+  }
+  .innerContents {
+    color: transparent;
+    height: 100px;
+    width: 100px;
+  }
+  .minWidth {
+    min-width: 50px;
+  }
+  .width {
+    width: 50px;
+  }
+  .minHeight {
+    min-height: 50px;
+    background: lightblue;
+  }
+  .height {
+    height: 50px;
+    background: lightblue;
+  }
+  .floatLBasic {
+    float: left;
+  }
+  .floatLWidth {
+    float: left;
+    width: 50px;
+  }
+  .iFlexBasic {
+    display: inline-flex;
+  }
+  .iFlexWidth {
+    display: inline-flex;
+    width: 50px;
+  }
+  .orthog {
+    writing-mode: vertical-lr;
+  }
+  </style>
+</head>
+<body>
+  <!--CSS Test: A size-contained button with no specified size should render at 0 height regardless of content.-->
+  <button><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained floated button with no specified size should render at 0px by 0px regardless of content.-->
+  <button class="floatLBasic"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained floated button with specified width and no specified height should render at given width and 0 height regardless of content.-->
+  <button class="floatLWidth"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained inline-flex button with no specified size should render at 0px by 0px regardless of content.-->
+  <button class="iFlexBasic"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained inline-flex button with specified width and no specified height should render at given width and 0 height regardless of content.-->
+  <button class="iFlexWidth"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained button should perform baseline alignment as if the container were empty.-->
+  outside before<button><div class="innerContents">inner</div></button>outside after
+  <br>
+
+  <!--CSS Test: A size-contained button with specified min-width should render at given min-width and zero height regardless of content.-->
+  <button class="minWidth"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained button with specified width should render at given width and zero height regardless of content.-->
+  <button class="width"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained button with specified min-height should render at given min-height regardless of content.-->
+  <button class="minHeight"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained button with specified height should render at given height regardless of content.-->
+  <button class="height"><div class="innerContents">inner</div></button>
+  <br>
+
+  <!--CSS Test: A size-contained button with vertical text should perform baseline alignment as if the container were empty.-->
+  s<button class="orthog"><div class="innerContents">inner</div></button>endtext
+  <br>
+
+  <!--CSS Test: A size-contained button with inner text should layout the text in the same manner as a container of the same type with identical contents.-->
+  <button class="height width">inside</button>
+</body>
+</html>
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -12,9 +12,10 @@ pref(layout.css.overflow-clip-box.enable
 == contain-paint-formatting-context-margin-001.html contain-paint-formatting-context-margin-001-ref.html
 == contain-paint-ignored-cases-internal-table-001a.html contain-paint-ignored-cases-internal-table-001-ref.html
 == contain-paint-ignored-cases-internal-table-001b.html contain-paint-ignored-cases-internal-table-001-ref.html
 == contain-paint-ignored-cases-no-principal-box-001.html contain-paint-ignored-cases-no-principal-box-001-ref.html
 == contain-paint-ignored-cases-ruby-containing-block-001.html contain-paint-ignored-cases-ruby-containing-block-001-ref.html
 == contain-paint-ignored-cases-ruby-stacking-and-clipping-001.html contain-paint-ignored-cases-ruby-stacking-and-clipping-001-ref.html
 == 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-multicol-001.html contain-size-multicol-001-ref.html