浏览代码

LibWeb: Create `::before` pseudo-element before element children

This allows any effects of `content` (eg quotes and counters) to happen
in the right order.

To make it work there are a couple of other changes needed:
- Skip nodes generated by ::before when constructing button layout.
- When in a flex parent, don't merge an inline text node into a previous
  one that is generated from a pseudo-element.
Sam Atkins 1 年之前
父节点
当前提交
493dd5d93c
共有 1 个文件被更改,包括 12 次插入3 次删除
  1. 12 3
      Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

+ 12 - 3
Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

@@ -70,7 +70,7 @@ static Layout::Node& insertion_parent_for_inline_node(Layout::NodeWithStyle& lay
         return layout_parent;
         return layout_parent;
 
 
     if (layout_parent.display().is_flex_inside() || layout_parent.display().is_grid_inside()) {
     if (layout_parent.display().is_flex_inside() || layout_parent.display().is_grid_inside()) {
-        if (layout_parent.last_child() && layout_parent.last_child()->is_anonymous() && layout_parent.last_child()->children_are_inline())
+        if (layout_parent.last_child() && layout_parent.last_child()->is_anonymous() && layout_parent.last_child()->children_are_inline() && !layout_parent.last_child()->is_generated())
             return *layout_parent.last_child();
             return *layout_parent.last_child();
         layout_parent.append_child(layout_parent.create_anonymous_wrapper());
         layout_parent.append_child(layout_parent.create_anonymous_wrapper());
         return *layout_parent.last_child();
         return *layout_parent.last_child();
@@ -319,6 +319,14 @@ ErrorOr<void> TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::
 
 
     auto* shadow_root = is<DOM::Element>(dom_node) ? verify_cast<DOM::Element>(dom_node).shadow_root_internal() : nullptr;
     auto* shadow_root = is<DOM::Element>(dom_node) ? verify_cast<DOM::Element>(dom_node).shadow_root_internal() : nullptr;
 
 
+    // Add node for the ::before pseudo-element.
+    if (is<DOM::Element>(dom_node) && layout_node->can_have_children()) {
+        auto& element = static_cast<DOM::Element&>(dom_node);
+        push_parent(verify_cast<NodeWithStyle>(*layout_node));
+        TRY(create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Before, AppendOrPrepend::Prepend));
+        pop_parent();
+    }
+
     if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children()) {
     if ((dom_node.has_children() || shadow_root) && layout_node->can_have_children()) {
         push_parent(verify_cast<NodeWithStyle>(*layout_node));
         push_parent(verify_cast<NodeWithStyle>(*layout_node));
         if (shadow_root) {
         if (shadow_root) {
@@ -412,6 +420,8 @@ ErrorOr<void> TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::
 
 
         Vector<JS::Handle<Node>> sequence;
         Vector<JS::Handle<Node>> sequence;
         for (auto child = parent.first_child(); child; child = child->next_sibling()) {
         for (auto child = parent.first_child(); child; child = child->next_sibling()) {
+            if (child->is_generated_for_before_pseudo_element())
+                continue;
             sequence.append(*child);
             sequence.append(*child);
         }
         }
 
 
@@ -426,11 +436,10 @@ ErrorOr<void> TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::
         parent.set_children_are_inline(false);
         parent.set_children_are_inline(false);
     }
     }
 
 
-    // Add nodes for the ::before and ::after pseudo-elements.
+    // Add nodes for the ::after pseudo-element.
     if (is<DOM::Element>(dom_node) && layout_node->can_have_children()) {
     if (is<DOM::Element>(dom_node) && layout_node->can_have_children()) {
         auto& element = static_cast<DOM::Element&>(dom_node);
         auto& element = static_cast<DOM::Element&>(dom_node);
         push_parent(verify_cast<NodeWithStyle>(*layout_node));
         push_parent(verify_cast<NodeWithStyle>(*layout_node));
-        TRY(create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Before, AppendOrPrepend::Prepend));
         TRY(create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::After, AppendOrPrepend::Append));
         TRY(create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::After, AppendOrPrepend::Append));
         pop_parent();
         pop_parent();
     }
     }