Bug 1514843 part 2: Honor 'contain:size' for scrollable elements. r=TYLin
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 29 Mar 2019 22:08:34 +0000
changeset 466866 f1d82b9507f76f5401b9c15961658c1290d6ac77
parent 466865 a4552bbd062b4c8e851bf353bdc69c6be1decc07
child 466867 877d344fd292bce9cf94a87731eb004c013739f6
push id112603
push usernerli@mozilla.com
push dateSat, 30 Mar 2019 09:35:57 +0000
treeherdermozilla-inbound@7c3183c56eb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersTYLin
bugs1514843
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1514843 part 2: Honor 'contain:size' for scrollable elements. r=TYLin 'contain:size' just means we should size these elements as if they had no contents -- i.e. wherever we derive the size of the scrollable frame from the size of its contents, we should pretend that its contents had zero size. Differential Revision: https://phabricator.services.mozilla.com/D25155
layout/generic/nsGfxScrollFrame.cpp
layout/reftests/w3c-css/submitted/contain/contain-size-block-002-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-block-002.html
layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-002-ref.html
layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-002.html
layout/reftests/w3c-css/submitted/contain/reftest.list
testing/web-platform/meta/css/css-contain/contain-size-011.html.ini
testing/web-platform/meta/css/css-contain/contain-size-061.html.ini
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -362,17 +362,19 @@ bool nsHTMLScrollFrame::TryLayout(Scroll
     scrollbar->SetScrollbarMediatorContent(mContent);
   }
   nscoord hScrollbarDesiredHeight =
       aAssumeHScroll ? hScrollbarPrefSize.height : 0;
   nscoord hScrollbarMinWidth = aAssumeHScroll ? hScrollbarMinSize.width : 0;
 
   // First, compute our inside-border size and scrollport size
   // XXXldb Can we depend more on ComputeSize here?
-  nsSize kidSize = aKidMetrics->PhysicalSize();
+  nsSize kidSize = aState->mReflowInput.mStyleDisplay->IsContainSize()
+                       ? nsSize(0, 0)
+                       : aKidMetrics->PhysicalSize();
   nsSize desiredInsideBorderSize;
   desiredInsideBorderSize.width =
       vScrollbarDesiredWidth + std::max(kidSize.width, hScrollbarMinWidth);
   desiredInsideBorderSize.height =
       hScrollbarDesiredHeight + std::max(kidSize.height, vScrollbarMinHeight);
   aState->mInsideBorderSize =
       ComputeInsideBorderSize(aState, desiredInsideBorderSize);
 
@@ -714,17 +716,19 @@ void nsHTMLScrollFrame::ReflowContents(S
   // time".
 
   // XXX Is this check really sufficient to catch all the incremental cases
   // where the ideal case doesn't have a scrollbar?
   if ((aState->mReflowedContentsWithHScrollbar ||
        aState->mReflowedContentsWithVScrollbar) &&
       aState->mVScrollbar != ShowScrollbar::Always &&
       aState->mHScrollbar != ShowScrollbar::Always) {
-    nsSize kidSize = kidDesiredSize.PhysicalSize();
+    nsSize kidSize = aState->mReflowInput.mStyleDisplay->IsContainSize()
+                         ? nsSize(0, 0)
+                         : kidDesiredSize.PhysicalSize();
     nsSize insideBorderSize = ComputeInsideBorderSize(aState, kidSize);
     nsRect scrolledRect = mHelper.GetUnsnappedScrolledRectInternal(
         kidDesiredSize.ScrollableOverflow(), insideBorderSize);
     if (nsRect(nsPoint(0, 0), insideBorderSize).Contains(scrolledRect)) {
       // Let's pretend we had no scrollbars coming in here
       kidDesiredSize.mOverflowAreas.Clear();
       ReflowScrolledFrame(aState, false, false, &kidDesiredSize);
     }
@@ -823,24 +827,29 @@ nscoord nsHTMLScrollFrame::GetIntrinsicV
   nsSize vScrollbarPrefSize(0, 0);
   GetScrollbarMetrics(bls, mHelper.mVScrollbarBox, nullptr,
                       &vScrollbarPrefSize);
   return vScrollbarPrefSize.width;
 }
 
 /* virtual */
 nscoord nsHTMLScrollFrame::GetMinISize(gfxContext* aRenderingContext) {
-  nscoord result = mHelper.mScrolledFrame->GetMinISize(aRenderingContext);
+  nscoord result = StyleDisplay()->IsContainSize()
+                       ? 0
+                       : mHelper.mScrolledFrame->GetMinISize(aRenderingContext);
   DISPLAY_MIN_INLINE_SIZE(this, result);
   return result + GetIntrinsicVScrollbarWidth(aRenderingContext);
 }
 
 /* virtual */
 nscoord nsHTMLScrollFrame::GetPrefISize(gfxContext* aRenderingContext) {
-  nscoord result = mHelper.mScrolledFrame->GetPrefISize(aRenderingContext);
+  nscoord result =
+      StyleDisplay()->IsContainSize()
+          ? 0
+          : mHelper.mScrolledFrame->GetPrefISize(aRenderingContext);
   DISPLAY_PREF_INLINE_SIZE(this, result);
   return NSCoordSaturatingAdd(result,
                               GetIntrinsicVScrollbarWidth(aRenderingContext));
 }
 
 nsresult nsHTMLScrollFrame::GetXULPadding(nsMargin& aMargin) {
   // Our padding hangs out on the inside of the scrollframe, but XUL doesn't
   // reaize that.  If we're stuck inside a XUL box, we need to claim no
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-block-002-ref.html
@@ -0,0 +1,88 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Reftest Reference</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <style>
+  .basic {
+    overflow: scroll;
+    position: relative;
+    border: 2px solid green;
+  }
+  .height-ref {
+    height: 60px;
+    background: lightblue;
+  }
+  .width-ref {
+    width: 60px;
+  }
+  .floatLBasic-ref {
+    float: left;
+  }
+  .floatLWidth-ref {
+    float: left;
+    width: 60px;
+  }
+  .flexBaselineCheck {
+    display: flex;
+    align-items: baseline;
+  }
+  .innerContents {
+    color: transparent;
+    height: 100px;
+    width: 100px;
+    position: absolute;
+  }
+  .zeroHeightContents {
+    color: transparent;
+    height: 0px;
+    width: 0px;
+  }
+  </style>
+</head>
+<body>
+  <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+       the testcase, and we simply use 'position: absolute' on the descendants
+       wherever the testcase has 'contain: size' on the container.  This
+       produces an accurate reference rendering, because out-of-flow content
+       doesn't contribute to the container's sizing, but does create scrollable
+       overflow (i.e. it produces scrollbars of the appropriate size for the
+       amount of overflow). -->
+  <div class="basic"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic height-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic height-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic width-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic width-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic floatLBasic-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic floatLWidth-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="flexBaselineCheck">
+    outside before
+    <div class="basic">
+      <!-- We use the out-of-flow "innerContents" to create the correct
+           amount of scrollable overflow to match the testcase, and we
+           use the smaller in-flow "zeroHeightContents" to provide a
+           baseline that we can use to verify the testcase's baseline
+           alignment position. -->
+      <div class="innerContents">inner</div>
+      <div class="zeroHeightContents">i</div>
+    </div>
+    outside after
+  </div>
+</body>
+</html>
copy from layout/reftests/w3c-css/submitted/contain/contain-size-block-001.html
copy to layout/reftests/w3c-css/submitted/contain/contain-size-block-002.html
--- a/layout/reftests/w3c-css/submitted/contain/contain-size-block-001.html
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-block-002.html
@@ -1,81 +1,93 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>CSS Test: 'contain: size' on block elements should cause them to be sized as if they had no contents</title>
+  <title>CSS Test: 'contain: size' on 'overflow:scroll' block elements should cause them to be sized as if they had no contents</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
   <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-block-001-ref.html">
+  <link rel="match" href="contain-size-block-002-ref.html">
   <style>
   .contain {
     contain: size;
-    border: 1em solid green;
-    background: red;
+    overflow: scroll;
+    border: 2px solid green;
   }
   .innerContents {
     color: transparent;
     height: 100px;
     width: 100px;
   }
   .minHeight {
-    min-height: 50px;
+    min-height: 60px;
     background: lightblue;
   }
   .height {
-    height: 50px;
+    height: 60px;
     background: lightblue;
   }
   .maxWidth {
-    max-width: 50px;
+    max-width: 60px;
   }
   .width {
-    width: 50px;
+    width: 60px;
   }
   .floatLBasic {
     float: left;
   }
   .floatLWidth {
     float: left;
-    width: 50px;
+    width: 60px;
   }
   .flexBaselineCheck {
     display: flex;
     align-items: baseline;
   }
   </style>
 </head>
 <body>
-  <!--CSS Test: A size-contained block element with no specified size should render at 0 height regardless of content.-->
+  <!-- NOTE: In all cases below, the expectation is that the size-contained
+       element should be sized as if it had no contents (while honoring
+       whatever sizing properties are provided). -->
+
+  <!--CSS Test: A size-contained scrollable block with no specified size.-->
   <div class="contain"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained block element with specified min-height should render at given min-height regardless of content.-->
+  <!--CSS Test: A size-contained scrollable block with specified min-height -->
   <div class="contain minHeight"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained block element with specified height should render at given height regardless of content.-->
+  <!--CSS Test: A size-contained scrollable block with specified height -->
   <div class="contain height"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained block element with specified max-width should render at given max-width and zero height regardless of content.-->
+  <!--CSS Test: A size-contained scrollable block with specified max-width -->
   <div class="contain maxWidth"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained block element with specified width should render at given width and zero height regardless of content.-->
+  <!--CSS Test: A size-contained scrollable block with specified width -->
   <div class="contain width"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained floated block element with no specified size should render at 0px by 0px regardless of content.-->
+  <!--CSS Test: A size-contained floated scrollable block with auto size -->
   <div class="contain floatLBasic"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained floated block element with specified width and no specified height should render at given width and 0 height regardless of content.-->
+  <!--CSS Test: A size-contained floated scrollable block with
+      specified width -->
   <div class="contain floatLWidth"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained block element should perform baseline alignment regularly.-->
+  <!--CSS Test: A size-contained scrollable block in a
+      baseline-aligning flex container: should size as if it's empty, but
+      still baseline-align using its contents' baseline -->
   <div class="flexBaselineCheck">
-  outside before<div class="contain"><div class="innerContents">inner</div></div>outside after
+    outside before
+    <div class="contain">
+      <div class="innerContents">inner</div>
+    </div>
+    outside after
   </div>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-002-ref.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Reftest Reference</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="author" title="Morgan Rae Reschenberg" href="mailto:mreschenberg@berkeley.edu">
+  <style>
+  .basic {
+    display: inline-block;
+    overflow: scroll;
+    position: relative;
+    border: 2px solid green;
+  }
+  .height-ref {
+    height: 60px;
+  }
+  .width-ref {
+    width: 60px;
+  }
+  .innerContents {
+    color: transparent;
+    height: 100px;
+    width: 100px;
+    position: absolute;
+  }
+  </style>
+</head>
+<body>
+  <!-- NOTE: In the reference-case scenarios here, we use the same DOM as in
+       the testcase, and we simply use 'position: absolute' on the descendants
+       wherever the testcase has 'contain: size' on the container.  This
+       produces an accurate reference rendering, because out-of-flow content
+       doesn't contribute to the container's sizing, but does create scrollable
+       overflow (i.e. it produces scrollbars of the appropriate size for the
+       amount of overflow). -->
+  <div class="basic"><div class="innerContents">inner</div></div>
+  <br>
+
+  outside before
+  <div class="basic"><div class="innerContents">inner</div></div>
+  outside after
+  <br>
+
+  <div class="basic height-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic height-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic width-ref"><div class="innerContents">inner</div></div>
+  <br>
+
+  <div class="basic width-ref"><div class="innerContents">inner</div></div>
+</body>
+</html>
copy from layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-001.html
copy to layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-002.html
--- a/layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-001.html
+++ b/layout/reftests/w3c-css/submitted/contain/contain-size-inline-block-002.html
@@ -1,59 +1,67 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <meta charset="utf-8">
-  <title>CSS Test: 'contain: size' on inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+  <title>CSS Test: 'contain: size' on 'overflow:scroll' inline-block elements should cause them to be sized as if they had no contents and baseline-aligned regularly.</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
   <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-inline-block-001-ref.html">
+  <link rel="match" href="contain-size-inline-block-002-ref.html">
   <style>
   .contain {
     display: inline-block;
+    overflow: scroll;
     contain:size;
-    border: 1em solid green;
-    background: red;
+    border: 2px solid green;
   }
   .innerContents {
     color: transparent;
     height: 100px;
     width: 100px;
   }
   .minHeight {
-    min-height: 50px;
+    min-height: 60px;
   }
   .height {
-    height: 50px;
+    height: 60px;
   }
   .minWidth {
-    min-width: 50px;
+    min-width: 60px;
   }
   .width {
-    width: 50px;
+    width: 60px;
   }
   </style>
 </head>
 <body>
-  <!--CSS Test: A size-contained inline-block element with no specified size should render at 0 height and 0 width regardless of content.-->
+  <!-- NOTE: In all cases below, the expectation is that the size-contained
+       element should be sized as if it had no contents (while honoring
+       whatever sizing properties are provided). -->
+
+  <!-- A size-contained scrollable inline-block with no specified size -->
   <div class="contain"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained inline-block element should perform baseline alignment regularly.-->
-  outside before<div class="contain"><div class="innerContents">inner</div></div>outside after
+  <!-- A size-contained scrollable inline-block should perform baseline
+       alignment regularly, based on contents' baseline. -->
+  outside before
+  <div class="contain"><div class="innerContents">inner</div></div>
+  outside after
   <br>
 
-  <!--CSS Test: A size-contained inline-block element with specified min-height should render at given min-height and 0 width regardless of content.-->
+  <!-- A size-contained scrollable inline-block with specified min-height -->
   <div class="contain minHeight"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained inline-block element with specified height should render at given height and 0 width regardless of content.-->
+  <!-- A size-contained scrollable inline-block with specified height -->
   <div class="contain height"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained inline-block element with specified min-width should render at given min-width and 0 height regardless of content.-->
+  <!-- A size-contained scrollable inline-block with specified min-width -->
   <div class="contain minWidth"><div class="innerContents">inner</div></div>
   <br>
 
-  <!--CSS Test: A size-contained inline-block element with specified width should render at given width and 0 height regardless of content.-->
+  <!-- A size-contained scrollable inline-block with specified width -->
   <div class="contain width"><div class="innerContents">inner</div></div>
 </body>
 </html>
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -15,17 +15,19 @@ pref(layout.css.overflow-clip-box.enable
 == 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
 fails == contain-size-button-001.html contain-size-button-001-ref.html # bug 1508441
 == contain-size-block-001.html contain-size-block-001-ref.html
+== contain-size-block-002.html contain-size-block-002-ref.html
 == contain-size-inline-block-001.html contain-size-inline-block-001-ref.html
+== contain-size-inline-block-002.html contain-size-inline-block-002-ref.html
 == contain-size-flex-001.html contain-size-flex-001-ref.html
 fuzzy-if(webrender&&winWidget,0-24,0-2) == contain-size-inline-flex-001.html contain-size-inline-flex-001-ref.html # bug 1474093
 == contain-size-grid-001.html contain-size-grid-001-ref.html
 == 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
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-contain/contain-size-011.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[contain-size-011.html]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-contain/contain-size-061.html.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[contain-size-061.html]
-  expected: FAIL