[css-pseudo] Support 'content' property in ::marker for LayoutNG

This patch adds support for a ::marker PseudoElement that obeys the
'content' property similarly to ::before and ::after.

This PseudoElement is only generated when 'content' is not 'normal',
otherwise the marker continues being an anonymous box. This will be
addressed in a follow-up patch.

Also, this only works in LayoutNG, since the legacy LayoutListMarker
doesn't allow children. Will also be addressed in a follow-up patch.

Spec: https://drafts.csswg.org/css-pseudo-4/#marker-pseudo

Bug: 457718

TEST=external/wpt/css/css-pseudo/marker-content-003.html
TEST=external/wpt/css/css-pseudo/marker-content-003b.html
TEST=external/wpt/css/css-pseudo/marker-content-004.html
TEST=external/wpt/css/css-pseudo/marker-content-006.html

Change-Id: I34097f9763cec626e898aff07681cd3e766afb49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1930835
Reviewed-by: Rune Lillesveen <futhark@chromium.org>
Commit-Queue: Oriol Brufau <obrufau@igalia.com>
Cr-Commit-Position: refs/heads/master@{#718609}
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index c873daf..9ecc1519 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -2880,6 +2880,7 @@
   }
   children_context.use_previous_in_flow = true;
 
+  AttachPseudoElement(kPseudoIdMarker, children_context);
   AttachPseudoElement(kPseudoIdBefore, children_context);
 
   if (ShadowRoot* shadow_root = GetShadowRoot()) {
@@ -2933,6 +2934,7 @@
     }
   }
 
+  DetachPseudoElement(kPseudoIdMarker, performing_reattach);
   DetachPseudoElement(kPseudoIdBefore, performing_reattach);
 
   // TODO(futhark): We need to traverse into IsUserActionElement() subtrees,
@@ -3078,6 +3080,7 @@
 
   if (child_change.TraversePseudoElements(*this)) {
     UpdatePseudoElement(kPseudoIdBackdrop, child_change);
+    UpdatePseudoElement(kPseudoIdMarker, child_change);
     UpdatePseudoElement(kPseudoIdBefore, child_change);
   }
 
@@ -3358,6 +3361,7 @@
     else
       RebuildChildrenLayoutTrees(*child_attacher);
     RebuildPseudoElementLayoutTree(kPseudoIdBefore, *child_attacher);
+    RebuildPseudoElementLayoutTree(kPseudoIdMarker, *child_attacher);
     RebuildPseudoElementLayoutTree(kPseudoIdBackdrop, *child_attacher);
     RebuildFirstLetterLayoutTree();
     ClearChildNeedsReattachLayoutTree();
diff --git a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
index 50fef4d..d2571c6 100644
--- a/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/first_letter_pseudo_element.cc
@@ -116,10 +116,6 @@
       !parent_layout_object->BehavesLikeBlockContainer())
     return nullptr;
 
-  LayoutObject* marker =
-      parent_layout_object->IsLayoutNGListItem()
-          ? ToLayoutNGListItem(parent_layout_object)->Marker()
-          : nullptr;
   // Drill down into our children and look for our first text child.
   LayoutObject* first_letter_text_layout_object =
       parent_layout_object->SlowFirstChild();
@@ -146,8 +142,8 @@
         break;
       first_letter_text_layout_object =
           first_letter_text_layout_object->NextSibling();
-    } else if (first_letter_text_layout_object->IsListMarker() ||
-               first_letter_text_layout_object == marker) {
+    } else if (first_letter_text_layout_object
+                   ->IsListMarkerIncludingNGInside()) {
       // The list item marker may have out-of-flow siblings inside an anonymous
       // block. Skip them to make sure we leave the anonymous block before
       // continuing looking for the first letter text.
@@ -186,9 +182,6 @@
       // setting up the first letter then.
       return nullptr;
     } else {
-      if (first_letter_text_layout_object->IsLayoutNGListItem())
-        marker = ToLayoutNGListItem(first_letter_text_layout_object)->Marker();
-
       first_letter_text_layout_object =
           first_letter_text_layout_object->SlowFirstChild();
     }
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
index ef14740..031c54abae 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal.cc
@@ -88,40 +88,74 @@
 }
 
 Node* LayoutTreeBuilderTraversal::NextSibling(const Node& node) {
-  if (node.IsBeforePseudoElement()) {
+  PseudoId pseudo_id = node.GetPseudoId();
+  Element* parent_element;
+  if (pseudo_id != kPseudoIdNone) {
     AssertPseudoElementParent(To<PseudoElement>(node));
-    if (Node* next = FlatTreeTraversal::FirstChild(*node.parentNode()))
-      return next;
-  } else {
-    if (node.IsAfterPseudoElement())
-      return nullptr;
-    if (Node* next = FlatTreeTraversal::NextSibling(node))
-      return next;
+    parent_element = DynamicTo<Element>(*node.parentNode());
   }
-
-  if (auto* parent_element =
-          DynamicTo<Element>(FlatTreeTraversal::Parent(node)))
-    return parent_element->GetPseudoElement(kPseudoIdAfter);
-
+  switch (pseudo_id) {
+    case kPseudoIdMarker:
+      if (Node* next = parent_element->GetPseudoElement(kPseudoIdBefore))
+        return next;
+      FALLTHROUGH;
+    case kPseudoIdBefore:
+      if (Node* next = FlatTreeTraversal::FirstChild(*parent_element))
+        return next;
+      FALLTHROUGH;
+    case kPseudoIdNone:
+      if (pseudo_id == kPseudoIdNone) {  // Not falling through
+        if (Node* next = FlatTreeTraversal::NextSibling(node))
+          return next;
+        parent_element = DynamicTo<Element>(FlatTreeTraversal::Parent(node));
+      }
+      if (parent_element) {
+        if (Node* next = parent_element->GetPseudoElement(kPseudoIdAfter))
+          return next;
+      }
+      FALLTHROUGH;
+    case kPseudoIdAfter:
+      break;
+    default:
+      NOTREACHED();
+  }
   return nullptr;
 }
 
 Node* LayoutTreeBuilderTraversal::PreviousSibling(const Node& node) {
-  if (node.IsAfterPseudoElement()) {
+  PseudoId pseudo_id = node.GetPseudoId();
+  Element* parent_element;
+  if (pseudo_id != kPseudoIdNone) {
     AssertPseudoElementParent(To<PseudoElement>(node));
-    if (Node* previous = FlatTreeTraversal::LastChild(*node.parentNode()))
-      return previous;
-  } else {
-    if (node.IsBeforePseudoElement())
-      return nullptr;
-    if (Node* previous = FlatTreeTraversal::PreviousSibling(node))
-      return previous;
+    parent_element = DynamicTo<Element>(*node.parentNode());
   }
-
-  if (auto* parent_element =
-          DynamicTo<Element>(FlatTreeTraversal::Parent(node)))
-    return parent_element->GetPseudoElement(kPseudoIdBefore);
-
+  switch (pseudo_id) {
+    case kPseudoIdAfter:
+      if (Node* previous = FlatTreeTraversal::LastChild(*parent_element))
+        return previous;
+      FALLTHROUGH;
+    case kPseudoIdNone:
+      if (pseudo_id == kPseudoIdNone) {  // Not falling through
+        if (Node* previous = FlatTreeTraversal::PreviousSibling(node))
+          return previous;
+        parent_element = DynamicTo<Element>(FlatTreeTraversal::Parent(node));
+      }
+      if (parent_element) {
+        if (Node* previous = parent_element->GetPseudoElement(kPseudoIdBefore))
+          return previous;
+      }
+      FALLTHROUGH;
+    case kPseudoIdBefore:
+      if (parent_element) {
+        if (Node* previous = parent_element->GetPseudoElement(kPseudoIdMarker))
+          return previous;
+      }
+      FALLTHROUGH;
+    case kPseudoIdMarker:
+      break;
+    default:
+      NOTREACHED();
+  }
   return nullptr;
 }
 
@@ -130,13 +164,13 @@
   if (!current_element)
     return FlatTreeTraversal::LastChild(node);
 
-  Node* last = current_element->GetPseudoElement(kPseudoIdAfter);
-  if (last)
+  if (Node* last = current_element->GetPseudoElement(kPseudoIdAfter))
     return last;
-  last = FlatTreeTraversal::LastChild(*current_element);
-  if (!last)
-    last = current_element->GetPseudoElement(kPseudoIdBefore);
-  return last;
+  if (Node* last = FlatTreeTraversal::LastChild(*current_element))
+    return last;
+  if (Node* last = current_element->GetPseudoElement(kPseudoIdBefore))
+    return last;
+  return current_element->GetPseudoElement(kPseudoIdMarker);
 }
 
 Node* LayoutTreeBuilderTraversal::Previous(const Node& node,
@@ -157,13 +191,13 @@
   if (!current_element)
     return FlatTreeTraversal::FirstChild(node);
 
-  Node* first = current_element->GetPseudoElement(kPseudoIdBefore);
-  if (first)
+  if (Node* first = current_element->GetPseudoElement(kPseudoIdMarker))
     return first;
-  first = FlatTreeTraversal::FirstChild(node);
-  if (!first)
-    first = current_element->GetPseudoElement(kPseudoIdAfter);
-  return first;
+  if (Node* first = current_element->GetPseudoElement(kPseudoIdBefore))
+    return first;
+  if (Node* first = FlatTreeTraversal::FirstChild(node))
+    return first;
+  return current_element->GetPseudoElement(kPseudoIdAfter);
 }
 
 static Node* NextAncestorSibling(const Node& node, const Node* stay_within) {
diff --git a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal_test.cc b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal_test.cc
index ad34ed7..ae5c6fb 100644
--- a/third_party/blink/renderer/core/dom/layout_tree_builder_traversal_test.cc
+++ b/third_party/blink/renderer/core/dom/layout_tree_builder_traversal_test.cc
@@ -39,6 +39,8 @@
 TEST_F(LayoutTreeBuilderTraversalTest, pseudos) {
   const char* const kHtml =
       "<style>"
+      "#top { display: list-item; }"
+      "#top::marker { content: \"baz\"; }"
       "#top::before { content: \"foo\"; }"
       "#top::after { content: \"bar\"; }"
       "</style>"
@@ -46,14 +48,17 @@
   SetupSampleHTML(kHtml);
 
   Element* top = GetDocument().QuerySelector("#top");
+  Element* marker = top->GetPseudoElement(kPseudoIdMarker);
   Element* before = top->GetPseudoElement(kPseudoIdBefore);
   Element* after = top->GetPseudoElement(kPseudoIdAfter);
-  EXPECT_EQ(before, LayoutTreeBuilderTraversal::Next(*top, nullptr));
+  EXPECT_EQ(marker, LayoutTreeBuilderTraversal::Next(*top, nullptr));
+  EXPECT_EQ(before, LayoutTreeBuilderTraversal::NextSibling(*marker));
   EXPECT_EQ(after, LayoutTreeBuilderTraversal::NextSibling(*before));
-  EXPECT_EQ(nullptr, LayoutTreeBuilderTraversal::PreviousSibling(*before));
   EXPECT_EQ(nullptr, LayoutTreeBuilderTraversal::NextSibling(*after));
   EXPECT_EQ(before, LayoutTreeBuilderTraversal::PreviousSibling(*after));
-  EXPECT_EQ(before, LayoutTreeBuilderTraversal::FirstChild(*top));
+  EXPECT_EQ(marker, LayoutTreeBuilderTraversal::PreviousSibling(*before));
+  EXPECT_EQ(nullptr, LayoutTreeBuilderTraversal::PreviousSibling(*marker));
+  EXPECT_EQ(marker, LayoutTreeBuilderTraversal::FirstChild(*top));
   EXPECT_EQ(after, LayoutTreeBuilderTraversal::LastChild(*top));
 }
 
diff --git a/third_party/blink/renderer/core/dom/node.h b/third_party/blink/renderer/core/dom/node.h
index b713f855..66a9719 100644
--- a/third_party/blink/renderer/core/dom/node.h
+++ b/third_party/blink/renderer/core/dom/node.h
@@ -286,6 +286,9 @@
   DISABLE_CFI_PERF bool IsAfterPseudoElement() const {
     return GetPseudoId() == kPseudoIdAfter;
   }
+  DISABLE_CFI_PERF bool IsMarkerPseudoElement() const {
+    return GetPseudoId() == kPseudoIdMarker;
+  }
   DISABLE_CFI_PERF bool IsFirstLetterPseudoElement() const {
     return GetPseudoId() == kPseudoIdFirstLetter;
   }
diff --git a/third_party/blink/renderer/core/dom/pseudo_element.cc b/third_party/blink/renderer/core/dom/pseudo_element.cc
index 248de8e..e90fa42 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element.cc
+++ b/third_party/blink/renderer/core/dom/pseudo_element.cc
@@ -70,6 +70,11 @@
                           (g_null_atom, "<pseudo:first-letter>", g_null_atom));
       return first_letter;
     }
+    case kPseudoIdMarker: {
+      DEFINE_STATIC_LOCAL(QualifiedName, marker,
+                          (g_null_atom, "<pseudo:marker>", g_null_atom));
+      return marker;
+    }
     default:
       NOTREACHED();
   }
@@ -81,11 +86,14 @@
 String PseudoElement::PseudoElementNameForEvents(PseudoId pseudo_id) {
   DEFINE_STATIC_LOCAL(const String, after, ("::after"));
   DEFINE_STATIC_LOCAL(const String, before, ("::before"));
+  DEFINE_STATIC_LOCAL(const String, marker, ("::marker"));
   switch (pseudo_id) {
     case kPseudoIdAfter:
       return after;
     case kPseudoIdBefore:
       return before;
+    case kPseudoIdMarker:
+      return marker;
     default:
       return g_empty_string;
   }
@@ -175,7 +183,8 @@
 
   const ComputedStyle& style = layout_object->StyleRef();
   if (style.StyleType() != kPseudoIdBefore &&
-      style.StyleType() != kPseudoIdAfter)
+      style.StyleType() != kPseudoIdAfter &&
+      style.StyleType() != kPseudoIdMarker)
     return;
   DCHECK(style.GetContentData());
 
diff --git a/third_party/blink/renderer/core/dom/pseudo_element_data.h b/third_party/blink/renderer/core/dom/pseudo_element_data.h
index a86bd42..a94702a 100644
--- a/third_party/blink/renderer/core/dom/pseudo_element_data.h
+++ b/third_party/blink/renderer/core/dom/pseudo_element_data.h
@@ -22,6 +22,7 @@
   void Trace(Visitor* visitor) {
     visitor->Trace(generated_before_);
     visitor->Trace(generated_after_);
+    visitor->Trace(generated_marker_);
     visitor->Trace(generated_first_letter_);
     visitor->Trace(backdrop_);
   }
@@ -29,19 +30,21 @@
  private:
   Member<PseudoElement> generated_before_;
   Member<PseudoElement> generated_after_;
+  Member<PseudoElement> generated_marker_;
   Member<PseudoElement> generated_first_letter_;
   Member<PseudoElement> backdrop_;
   DISALLOW_COPY_AND_ASSIGN(PseudoElementData);
 };
 
 inline bool PseudoElementData::HasPseudoElements() const {
-  return generated_before_ || generated_after_ || backdrop_ ||
-         generated_first_letter_;
+  return generated_before_ || generated_after_ || generated_marker_ ||
+         backdrop_ || generated_first_letter_;
 }
 
 inline void PseudoElementData::ClearPseudoElements() {
   SetPseudoElement(kPseudoIdBefore, nullptr);
   SetPseudoElement(kPseudoIdAfter, nullptr);
+  SetPseudoElement(kPseudoIdMarker, nullptr);
   SetPseudoElement(kPseudoIdBackdrop, nullptr);
   SetPseudoElement(kPseudoIdFirstLetter, nullptr);
 }
@@ -59,6 +62,11 @@
         generated_after_->Dispose();
       generated_after_ = element;
       break;
+    case kPseudoIdMarker:
+      if (generated_marker_)
+        generated_marker_->Dispose();
+      generated_marker_ = element;
+      break;
     case kPseudoIdBackdrop:
       if (backdrop_)
         backdrop_->Dispose();
@@ -80,6 +88,8 @@
     return generated_before_;
   if (kPseudoIdAfter == pseudo_id)
     return generated_after_;
+  if (kPseudoIdMarker == pseudo_id)
+    return generated_marker_;
 // Workaround for CPU bug. This avoids compiler optimizing
 // this group of if conditions into switch. See http://crbug.com/855390.
 #if defined(ARCH_CPU_ARMEL)
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index 3f4cd4a..ceb6d30 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -161,6 +161,7 @@
       break;
     case kPseudoIdBefore:
     case kPseudoIdAfter:
+    case kPseudoIdMarker:
       break;
     default:
       return false;  // Counters are forbidden from all other pseudo elements.
@@ -483,7 +484,8 @@
                          // pseudo elements
       PseudoId container_style = before_after_container->StyleRef().StyleType();
       if ((container_style == kPseudoIdBefore) ||
-          (container_style == kPseudoIdAfter))
+          (container_style == kPseudoIdAfter) ||
+          (container_style == kPseudoIdMarker))
         break;
       before_after_container = before_after_container->Parent();
     }
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 889954a..ef2fc8c 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -223,6 +223,8 @@
     }
     image->SetStyleInternal(nullptr);
     return image;
+  } else if (element->GetPseudoId() == kPseudoIdMarker) {
+    return LayoutObjectFactory::CreateListMarker(*element, style, legacy);
   }
 
   switch (style.Display()) {
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc
index c23306d..00524e1 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -22,7 +22,9 @@
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_progress.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
@@ -90,6 +92,23 @@
       node, style, legacy);
 }
 
+LayoutObject* LayoutObjectFactory::CreateListMarker(Node& node,
+                                                    const ComputedStyle& style,
+                                                    LegacyLayout legacy) {
+  // TODO(obrufau): allow ::marker pseudo-elements to generate legacy layout.
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled() ||
+      legacy == LegacyLayout::kForce)
+    return nullptr;
+  // TODO(obrufau): markers may be forced to be inside despite having
+  // `list-style-position: outside`.
+  if (style.ListStylePosition() == EListStylePosition::kInside) {
+    return CreateObject<LayoutObject, LayoutNGInsideListMarker,
+                        LayoutNGInsideListMarker>(node, style, legacy);
+  }
+  return CreateObject<LayoutObject, LayoutNGListMarker, LayoutNGListMarker>(
+      node, style, legacy);
+}
+
 LayoutTableCaption* LayoutObjectFactory::CreateTableCaption(
     Node& node,
     const ComputedStyle& style,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h
index 3fbd47b..4fc7ac0f 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -14,6 +14,7 @@
 class ComputedStyle;
 class LayoutBlock;
 class LayoutBlockFlow;
+class LayoutObject;
 enum class LegacyLayout;
 class LayoutProgress;
 class LayoutTableCaption;
@@ -43,6 +44,9 @@
   static LayoutBlockFlow* CreateListItem(Node&,
                                          const ComputedStyle&,
                                          LegacyLayout);
+  static LayoutObject* CreateListMarker(Node&,
+                                        const ComputedStyle&,
+                                        LegacyLayout);
   static LayoutTableCaption* CreateTableCaption(Node&,
                                                 const ComputedStyle&,
                                                 LegacyLayout);
diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h b/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
index ec19ee3..0ce5f75 100644
--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
+++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
@@ -22,8 +22,8 @@
 
 #if DCHECK_IS_ON()
   void AddChild(LayoutObject* new_child, LayoutObject* before_child) override {
-    // List marker should have at most one child.
-    DCHECK(!FirstChild());
+    // Anonymous list marker should have at most one child.
+    DCHECK(GetNode() || !FirstChild());
     LayoutInline::AddChild(new_child, before_child);
   }
 #endif
diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
index f3107a3..a5c7387b 100644
--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
@@ -159,6 +159,14 @@
     marker_style = ComputedStyle::Create();
     marker_style->InheritFrom(style);
   }
+  if (marker_style->GetContentData()) {
+    // Don't create an anonymous layout for the marker, it will be generated
+    // by the ::marker pseudo-element.
+    DestroyMarker();
+    marker_type_ = kStatic;
+    is_marker_text_updated_ = true;
+    return;
+  }
   if (IsInside()) {
     if (marker_ && !marker_->IsLayoutInline())
       DestroyMarker();
@@ -205,7 +213,16 @@
   for (LayoutObject* parent = marker.Parent(); parent;
        parent = parent->Parent()) {
     if (parent->IsLayoutNGListItem()) {
-      DCHECK(ToLayoutNGListItem(parent)->Marker() == &marker);
+#if DCHECK_IS_ON()
+      LayoutObject* parent_marker = ToLayoutNGListItem(parent)->Marker();
+      if (parent_marker) {
+        DCHECK(!marker.GetNode());
+        DCHECK_EQ(ToLayoutNGListItem(parent)->Marker(), &marker);
+      } else {
+        DCHECK(marker.GetNode()->IsMarkerPseudoElement());
+        DCHECK_EQ(marker.GetNode()->parentElement()->GetLayoutBox(), parent);
+      }
+#endif
       return ToLayoutNGListItem(parent);
     }
     // These DCHECKs are not critical but to ensure we cover all cases we know.
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index f616d43..e84d5e4 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2511,6 +2511,8 @@
       return false;
     if (IsEnsuredInDisplayNone())
       return false;
+    if (pseudo == kPseudoIdMarker)
+      return Display() == EDisplay::kListItem;
     if (Display() != EDisplay::kContents)
       return true;
     // For display: contents elements, we still need to generate ::before and
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
index a998db0..b44b390 100644
--- a/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
+++ b/third_party/blink/web_tests/FlagExpectations/disable-layout-ng
@@ -60,6 +60,12 @@
 crbug.com/591099 external/wpt/css/css-position/static-position/vrl-rtl-ltr.tentative.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-position/static-position/vrl-rtl-rtl.html [ Failure ]
 
+### external/wpt/css/css-pseudo/
+crbug.com/457718 external/wpt/css/css-pseudo/marker-content-003.html [ Failure ]
+crbug.com/457718 external/wpt/css/css-pseudo/marker-content-003b.html [ Failure ]
+crbug.com/457718 external/wpt/css/css-pseudo/marker-content-004.html [ Failure ]
+crbug.com/457718 external/wpt/css/css-pseudo/marker-content-006.html [ Failure ]
+
 ### external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Failure ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index d782c58..6116404 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -3888,12 +3888,8 @@
 crbug.com/792446 external/wpt/css/css-multicol/multicol-span-float-001.xht [ Failure ]
 crbug.com/964183 external/wpt/css/css-multicol/multicol-width-005.html [ Failure ]
 
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-002.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-003.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-003b.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-004.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-005.html [ Failure ]
-crbug.com/457718 external/wpt/css/css-pseudo/marker-content-006.html [ Failure ]
+crbug.com/796961 external/wpt/css/css-pseudo/marker-content-002.html [ Failure ]
+crbug.com/796961 external/wpt/css/css-pseudo/marker-content-005.html [ Failure ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-content-007.html [ Failure ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-content-008.html [ Failure ]
 crbug.com/457718 external/wpt/css/css-pseudo/marker-content-009.html [ Failure ]