Bug 1506163 - Do not span column-span:all element across all columns if it's under different block formatting context. r=bz
authorTing-Yu Lin <tlin@mozilla.com>
Fri, 16 Nov 2018 16:31:22 -0800
changeset 503537 a5e00e5b4635a19e9fb4ed3566565504338384c6
parent 503536 8943bbe0793f69ee9622bd26c9cdea4bbe07d65c
child 503538 295cd66cea8f4d957f0c77c821c4dfb1abc7e588
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1506163
milestone65.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 1506163 - Do not span column-span:all element across all columns if it's under different block formatting context. r=bz multicol-span-all-004-ref.html is the same as multicol-span-all-004.html except for the "column-span" value in h3. Differential Revision: https://phabricator.services.mozilla.com/D12192
layout/base/crashtests/1506163.html
layout/base/crashtests/crashtests.list
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsFrameStateBits.h
testing/web-platform/meta/css/css-multicol/multicol-span-all-004.html.ini
testing/web-platform/tests/css/css-multicol/multicol-span-all-004-ref.html
testing/web-platform/tests/css/css-multicol/multicol-span-all-004.html
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1506163.html
@@ -0,0 +1,7 @@
+<li style="column-count: 1">
+<summary style="overflow-x: scroll">
+<div style="column-span: all">
+<canvas>
+<meta
+charset="UTF-8"
+<!-- a -->
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -543,9 +543,10 @@ load 1469354.html
 pref(layout.accessiblecaret.enabled,true) load 1472020.html
 load 1472027.html
 load 1477847.html
 load 1489149.html
 load 1490037.html
 load 1494332.html
 load 1494030.html
 load 1505420.html
+pref(layout.css.column-span.enabled,true) load 1506163.html
 pref(layout.css.column-span.enabled,true) load 1506204.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -11169,24 +11169,27 @@ nsCSSFrameConstructor::ConstructBlock(ns
   nsFrameConstructorSaveState absoluteSaveState;
   (*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
   if (aPositionedFrameForAbsPosContainer) {
     //    NS_ASSERTION(aRelPos, "should have made area frame for this");
     aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
   }
 
   // Ensure all the children in the multi-column subtree are tagged with
-  // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR, except for those children in the
-  // column-span subtree. InitAndRestoreFrame() will add
+  // NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR, except for those children in a new
+  // block formatting context. InitAndRestoreFrame() will add
   // mAdditionalStateBits for us.
   AutoRestore<nsFrameState> savedStateBits(aState.mAdditionalStateBits);
   if (StaticPrefs::layout_css_column_span_enabled()) {
+    // Multi-column container creates new block formatting context, so check
+    // needsColumn first to make sure we have the bit set when creating frames
+    // for the elements having style like "columns:3; column-span:all;".
     if (needsColumn) {
       aState.mAdditionalStateBits |= NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR;
-    } else if (blockFrame->IsColumnSpan()) {
+    } else if (blockFrame->HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS)) {
       aState.mAdditionalStateBits &= ~NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR;
     }
   }
 
   // Process the child content
   nsFrameItems childItems;
   ProcessChildren(aState, aContent, aComputedStyle, blockFrame, true,
                   childItems, true, aPendingBinding);
@@ -11387,24 +11390,32 @@ nsCSSFrameConstructor::FinishBuildingCol
 bool
 nsCSSFrameConstructor::MayNeedToCreateColumnSpanSiblings(
   nsContainerFrame* aBlockFrame,
   const nsFrameList& aChildList)
 {
   MOZ_ASSERT(StaticPrefs::layout_css_column_span_enabled(),
              "Call this only when layout.css.column-span.enabled is true!");
 
-  if (aBlockFrame->IsColumnSpan() ||
-      !aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
-    // The children of a column-span never need to be further processed even
-    // if there is a nested column-span child. Because a column-span always
-    // creates its own block formatting context, a nested column-span child
-    // won't be in the same block formatting context with the nearest
-    // multi-column ancestor. This is the same case as if the column-span is
-    // outside of a multi-column hierarchy.
+  if (!aBlockFrame->HasAnyStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)) {
+    // The block frame isn't in a multi-column block formatting context.
+    return false;
+  }
+
+  if (aBlockFrame->HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS) &&
+      aBlockFrame->Style()->GetPseudo() != nsCSSAnonBoxes::columnContent()) {
+    // The block creates its own block formatting context, and is not the block
+    // representing actual column contents.
+    //
+    // For example, the children of a column-span never need to be further
+    // processed even if there is a nested column-span child. Because a
+    // column-span always creates its own block formatting context, a nested
+    // column-span child won't be in the same block formatting context with the
+    // nearest multi-column ancestor. This is the same case as if the
+    // column-span is outside of a multi-column hierarchy.
     return false;
   }
 
   if (aChildList.IsEmpty()) {
     // No child needs to be processed.
     return false;
   }
 
@@ -11414,17 +11425,17 @@ nsCSSFrameConstructor::MayNeedToCreateCo
   }
 
   if (aBlockFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
     // No need to deal with an out-of-flow frame because column-span applies
     // only to in-flow elements per spec.
     return false;
   }
 
-  // Need to actually look into the child items.
+  // Need to actually look into the child list.
   return true;
 }
 
 nsFrameItems
 nsCSSFrameConstructor::CreateColumnSpanSiblings(nsFrameConstructorState& aState,
                                                 nsContainerFrame* aInitialBlock,
                                                 nsFrameList& aChildList,
                                                 nsIFrame* aPositionedFrame)
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -220,21 +220,24 @@ FRAME_STATE_BIT(Generic, 41, NS_FRAME_FO
 FRAME_STATE_BIT(Generic, 42, NS_FRAME_FONT_INFLATION_FLOW_ROOT)
 
 // This bit is set on SVG frames that are laid out using SVG's coordinate
 // system based layout (as opposed to any of the CSS layout models). Note that
 // this does not include nsSVGOuterSVGFrame since it takes part is CSS layout.
 FRAME_STATE_BIT(Generic, 43, NS_FRAME_SVG_LAYOUT)
 
 // This bit is set if a frame has a multi-column ancestor (i.e.
-// ColumnSetWrapperFrame) within the same block formatting context. A
-// top-level ColumnSetWrapperFrame doesn't have this bit set, whereas a
-// ColumnSetWrapperFrame nested inside a column does have this bit set. All
-// the children of the column-spans do not have this bit set because they
-// are in a new block formatting context created by column-spans.
+// ColumnSetWrapperFrame) within the same block formatting context. A top-level
+// ColumnSetWrapperFrame doesn't have this bit set, whereas a
+// ColumnSetWrapperFrame nested inside a column does have this bit set.
+//
+// All the children of the column-spanners or any other type of frames which
+// create their own block formatting context do not have this bit set because
+// they are not in the same block formatting context created by a multi-column
+// ancestor.
 FRAME_STATE_BIT(Generic, 44, NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR)
 
 // Bits 45 is currently unused, but be kind and check with bug 1465474
 // first please :-)
 
 // This bit indicates that we're tracking visibility for this frame, and that
 // the frame has a VisibilityStateProperty property.
 FRAME_STATE_BIT(Generic, 46, NS_FRAME_VISIBILITY_IS_TRACKED)
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/meta/css/css-multicol/multicol-span-all-004.html.ini
@@ -0,0 +1,2 @@
+[multicol-span-all-004.html]
+  prefs: [layout.css.column-span.enabled:true]
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-004-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: column-span:all should act like column-span:none in different block formatting context</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  #column {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 600px;
+    outline: 1px solid black;
+  }
+  h3 {
+    column-span: none;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <body onload="runTest();">
+    <article id="column">
+      <div>block1</div>
+      <div style="display: inline-block;">
+        <h3>non-spanner</h3>
+      </div>
+      <div style="overflow: hidden;">
+        <h3>non-spanner</h3>
+      </div>
+      <div style="column-span: all; outline: 1px solid green;">
+        Spanner
+        <h3>non-spanner in a spanner</h3>
+      </div>
+      <div>block2</div>
+    </article>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-multicol/multicol-span-all-004.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: column-span:all should act like column-span:none in different block formatting context</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="match" href="multicol-span-all-004-ref.html">
+  <meta name="assert" content="This test checks a column-span:all element should act like column-span: none if it's under different block formatting context.">
+
+  <style>
+  #column {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 600px;
+    outline: 1px solid black;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <body onload="runTest();">
+    <article id="column">
+      <div>block1</div>
+      <div style="display: inline-block;">
+        <h3>non-spanner</h3>
+      </div>
+      <div style="overflow: hidden;">
+        <h3>non-spanner</h3>
+      </div>
+      <div style="column-span: all; outline: 1px solid green;">
+        Spanner
+        <h3>non-spanner in a spanner</h3>
+      </div>
+      <div>block2</div>
+    </article>
+  </body>
+</html>