Bug 1494100 Part 3 - Implement "contain:size" for ColumnSetWrapperFrame. r=dholbert
authorTing-Yu Lin <tlin@mozilla.com>
Wed, 08 May 2019 22:58:39 +0000
changeset 531991 6cc70607d8afbe3a56fc6a3f3bc6544da4c8dba5
parent 531990 93fd1b5a5a025a54f109c8ab76d17ee1e6f860d1
child 531992 57b5cbfc0d7a0857e896d0a41c366fc7a4d77da0
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1494100
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 1494100 Part 3 - Implement "contain:size" for ColumnSetWrapperFrame. r=dholbert Add multicol-width-004.html and multicol-width-005.html to test "width: min-content" and "width: max-content" with column-span:all children. There's no size containment in these tests. Note it may be worth to reuse nsBlockFrame's mCachedMinISize and mCachedPrefISize to cache intrinsic size for ColumnSetWrapperFrame, but this can be done separately. Differential Revision: https://phabricator.services.mozilla.com/D29616
layout/generic/ColumnSetWrapperFrame.cpp
layout/generic/ColumnSetWrapperFrame.h
layout/reftests/w3c-css/submitted/contain/reftest.list
testing/web-platform/meta/css/css-multicol/multicol-width-004.html.ini
testing/web-platform/meta/css/css-multicol/multicol-width-005.html.ini
testing/web-platform/tests/css/css-multicol/multicol-width-004-ref.html
testing/web-platform/tests/css/css-multicol/multicol-width-004.html
testing/web-platform/tests/css/css-multicol/multicol-width-005-ref.html
testing/web-platform/tests/css/css-multicol/multicol-width-005.html
--- a/layout/generic/ColumnSetWrapperFrame.cpp
+++ b/layout/generic/ColumnSetWrapperFrame.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 #include "ColumnSetWrapperFrame.h"
 
+#include "mozilla/ColumnUtils.h"
 #include "mozilla/PresShell.h"
 #include "nsContentUtils.h"
 #include "nsIFrame.h"
 #include "nsIFrameInlines.h"
 
 using namespace mozilla;
 
 nsBlockFrame* NS_NewColumnSetWrapperFrame(PresShell* aPresShell,
@@ -144,16 +145,84 @@ void ColumnSetWrapperFrame::MarkIntrinsi
 
   // The parent's method adds NS_BLOCK_NEEDS_BIDI_RESOLUTION to all our
   // continuations. Clear the bit because we don't want to call ResolveBidi().
   for (nsIFrame* f = FirstContinuation(); f; f = f->GetNextContinuation()) {
     f->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
   }
 }
 
+nscoord ColumnSetWrapperFrame::GetMinISize(gfxContext* aRenderingContext) {
+  nscoord iSize = 0;
+  DISPLAY_MIN_INLINE_SIZE(this, iSize);
+
+  if (StyleDisplay()->IsContainSize()) {
+    // If we're size-contained, we determine our minimum intrinsic size purely
+    // from our column styling, as if we had no descendants. This should match
+    // what happens in nsColumnSetFrame::GetMinISize in an actual no-descendants
+    // scenario.
+    const nsStyleColumn* colStyle = StyleColumn();
+    if (colStyle->mColumnWidth.IsLength()) {
+      // As available inline size reduces to zero, our number of columns reduces
+      // to one, so no column gaps contribute to our minimum intrinsic size.
+      // Also, column-width doesn't set a lower bound on our minimum intrinsic
+      // size, either. Just use 0 because we're size-contained.
+      iSize = 0;
+    } else {
+      MOZ_ASSERT(colStyle->mColumnCount != nsStyleColumn::kColumnCountAuto,
+                 "column-count and column-width can't both be auto!");
+      // As available inline size reduces to zero, we still have mColumnCount
+      // columns, so compute our minimum intrinsic size based on N zero-width
+      // columns, with specified gap size between them.
+      const nscoord colGap =
+          ColumnUtils::GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
+      iSize = ColumnUtils::IntrinsicISize(colStyle->mColumnCount, colGap, 0);
+    }
+  } else {
+    for (nsIFrame* f : PrincipalChildList()) {
+      iSize = std::max(iSize, f->GetMinISize(aRenderingContext));
+    }
+  }
+
+  return iSize;
+}
+
+nscoord ColumnSetWrapperFrame::GetPrefISize(gfxContext* aRenderingContext) {
+  nscoord iSize = 0;
+  DISPLAY_PREF_INLINE_SIZE(this, iSize);
+
+  if (StyleDisplay()->IsContainSize()) {
+    const nsStyleColumn* colStyle = StyleColumn();
+    nscoord colISize;
+    if (colStyle->mColumnWidth.IsLength()) {
+      colISize =
+          ColumnUtils::ClampUsedColumnWidth(colStyle->mColumnWidth.AsLength());
+    } else {
+      MOZ_ASSERT(colStyle->mColumnCount != nsStyleColumn::kColumnCountAuto,
+                 "column-count and column-width can't both be auto!");
+      colISize = 0;
+    }
+
+    // If column-count is auto, assume one column.
+    const uint32_t numColumns =
+        colStyle->mColumnCount == nsStyleColumn::kColumnCountAuto
+            ? 1
+            : colStyle->mColumnCount;
+    const nscoord colGap =
+        ColumnUtils::GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
+    iSize = ColumnUtils::IntrinsicISize(numColumns, colGap, colISize);
+  } else {
+    for (nsIFrame* f : PrincipalChildList()) {
+      iSize = std::max(iSize, f->GetPrefISize(aRenderingContext));
+    }
+  }
+
+  return iSize;
+}
+
 #ifdef DEBUG
 
 /* static */
 void ColumnSetWrapperFrame::AssertColumnSpanWrapperSubtreeIsSane(
     const nsIFrame* aFrame) {
   MOZ_ASSERT(aFrame->IsColumnSpan(), "aFrame is not column-span?");
 
   if (!nsLayoutUtils::GetStyleFrame(const_cast<nsIFrame*>(aFrame))
--- a/layout/generic/ColumnSetWrapperFrame.h
+++ b/layout/generic/ColumnSetWrapperFrame.h
@@ -49,16 +49,20 @@ class ColumnSetWrapperFrame final : publ
 
   void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
                     nsFrameList& aFrameList) override;
 
   void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
 
   void MarkIntrinsicISizesDirty() override;
 
+  nscoord GetMinISize(gfxContext* aRenderingContext) override;
+
+  nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+
  private:
   explicit ColumnSetWrapperFrame(ComputedStyle* aStyle,
                                  nsPresContext* aPresContext);
   ~ColumnSetWrapperFrame() override = default;
 
 #ifdef DEBUG
   static void AssertColumnSpanWrapperSubtreeIsSane(const nsIFrame* aFrame);
 
--- a/layout/reftests/w3c-css/submitted/contain/reftest.list
+++ b/layout/reftests/w3c-css/submitted/contain/reftest.list
@@ -50,11 +50,11 @@ fuzzy-if(webrender&&winWidget,0-24,0-2) 
 == contain-layout-suppress-baseline-001.html contain-layout-suppress-baseline-001-ref.html
 fails == contain-layout-suppress-baseline-002.html contain-layout-suppress-baseline-002-ref.html # bug 1508441
 
 # The following lines are duplicates of other lines from further up in this
 # manifest. They're listed again here so we can re-run these tests with
 # column-span enabled. These lines can be removed once the pref becomes
 # default-enabled (Bug 1426010).
 default-preferences pref(layout.css.column-span.enabled,true)
-fails == contain-size-multicol-002.html contain-size-multicol-002-ref.html # Bug 1494100
-fails == contain-size-multicol-003.html contain-size-multicol-003-ref.html # Bug 1494100
+== contain-size-multicol-002.html contain-size-multicol-002-ref.html
+== contain-size-multicol-003.html contain-size-multicol-003-ref.html
 default-preferences
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-multicol/multicol-width-004.html.ini
@@ -0,0 +1,2 @@
+[multicol-width-004.html]
+  prefs: [layout.css.column-span.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-multicol/multicol-width-005.html.ini
@@ -0,0 +1,2 @@
+[multicol-width-005.html]
+  prefs: [layout.css.column-span.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-width-004-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Ref: Test width:min-content for a multi-column container with column-span:all children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  article {
+    border: 1px solid black;
+  }
+  .block {
+    width: 100px;
+    background-color: yellow;
+  }
+  .spanner {
+    column-span: all;
+    background-color: lime;
+  }
+  </style>
+
+  <!-- Case 1 -->
+  <article style="width: 80px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 2 -->
+  <article style="width: 150px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 150px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 3 -->
+  <article style="width: 210px;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 4 -->
+  <article style="width: 250px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 250px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-width-004.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test width:min-content for a multi-column container with column-span:all children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-properties">
+  <link rel="match" href="multicol-width-004-ref.html">
+  <meta name="assert" content="This test checks the width:min-content for a multi-column container is calculated correctly.">
+
+  <style>
+  article {
+    width: min-content;
+    border: 1px solid black;
+    column-gap: 10px;
+  }
+  .block {
+    width: 100px;
+    background-color: yellow;
+  }
+  .spanner {
+    column-span: all;
+    background-color: lime;
+  }
+  </style>
+
+  <!-- Case 1: column-width is specified, and spanner's width is less than
+       column-width, so <article>'s expected width is 80px. -->
+  <article style="column-width: 80px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 2: like case 1, but spanner's width is larger than column-width.
+       Thus <article>'s expected width is 150px; -->
+  <article style="column-width: 80px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 150px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 3: column-count is specified. Thus <article>'s expected width is two
+       column boxes wide plus the column-gap, i.e. 100px*2 + 10px = 210px. -->
+  <article style="column-count: 2;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 4: like case 3, but the spanner's width is larger. Thus <article>'s
+       expected width is 250px. -->
+  <article style="column-count: 2;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 250px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-width-005-ref.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Ref: Test width:max-content for a multi-column container with column-span:all children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  article {
+    border: 1px solid black;
+  }
+  .block {
+    width: 100px;
+    background-color: yellow;
+  }
+  .spanner {
+    column-span: all;
+    background-color: lime;
+  }
+  </style>
+
+  <!-- Case 1 -->
+  <article style="width: 80px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 2 -->
+  <article style="width: 120px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 3 -->
+  <article style="width: 150px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 150px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 4 -->
+  <article style="width: 210px;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 4 -->
+  <article style="width: 230px;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 6 -->
+  <article style="width: 250px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 250px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-width-005.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test width:max-content for a multi-column container with column-span:all children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="help" href="https://drafts.csswg.org/css-sizing-3/#sizing-properties">
+  <link rel="match" href="multicol-width-005-ref.html">
+  <meta name="assert" content="This test checks the width:max-content for a multi-column container is calculated correctly.">
+
+  <style>
+  article {
+    width: max-content;
+    border: 1px solid black;
+    column-gap: 10px;
+  }
+  .block {
+    width: 100px;
+    background-color: yellow;
+  }
+  .spanner {
+    column-span: all;
+    background-color: lime;
+  }
+  </style>
+
+  <!-- Case 1: column-width is specified, and "column-count:auto" is considered
+       one column, so <article>'s expected width is 80px. -->
+  <article style="column-width: 80px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 2: column-width is specified, and no other children are wider than
+       the column-width. Thus <article>'s expected width is 120px. -->
+  <article style="column-width: 120px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 50px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 3: like case 2, but the spanner's width is larger than column-width.
+       Thus <article>'s expected width is 150px; -->
+  <article style="column-width: 120px;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 150px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 4: column-count is specified. <article>'s expected width is two
+       column boxes wide plus the column-gap, i.e. 100px*2 + 10px = 210px. -->
+  <article style="column-count: 2;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 5: column-count is specified, and column-width is larger than the
+       column-box's width. Thus <article>'s expected width is column-width plus
+       the column-gap, i.e. 110px*2 + 10px = 230px. -->
+  <article style="column-count: 2; column-width: 110px;">
+    <div class="block">block1</div>
+    <div class="spanner">spanner</div>
+    <div class="block">block2</div>
+  </article>
+  <br>
+
+  <!-- Case 6: like case 4, but the spanner's width is larger. Thus <article>'s
+       expected width is 250px. -->
+  <article style="column-count: 2;">
+    <div class="block">block1</div>
+    <div class="spanner" style="width: 250px;">spanner</div>
+    <div class="block">block2</div>
+  </article>
+</html>