Ver código fonte

LibWeb: Split out helper functions in TreeBuilder::create_layout_tree()

Let's make this function a little easier to understand by splitting out
helpers into separate functions.
Andreas Kling 2 anos atrás
pai
commit
4fdfaff4ca

+ 69 - 64
Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp

@@ -110,6 +110,70 @@ static Layout::Node& insertion_parent_for_block_node(Layout::NodeWithStyle& layo
     return layout_parent;
 }
 
+void TreeBuilder::insert_node_into_inline_or_block_ancestor(Layout::Node& node, AppendOrPrepend mode)
+{
+    if (node.is_inline() && !(node.is_inline_block() && m_ancestor_stack.last().computed_values().display().is_flex_inside())) {
+        // Inlines can be inserted into the nearest ancestor.
+        auto& insertion_point = insertion_parent_for_inline_node(m_ancestor_stack.last());
+        if (mode == AppendOrPrepend::Prepend)
+            insertion_point.prepend_child(node);
+        else
+            insertion_point.append_child(node);
+        insertion_point.set_children_are_inline(true);
+    } else {
+        // Non-inlines can't be inserted into an inline parent, so find the nearest non-inline ancestor.
+        auto& nearest_non_inline_ancestor = [&]() -> Layout::NodeWithStyle& {
+            for (auto& ancestor : m_ancestor_stack.in_reverse()) {
+                if (!ancestor.is_inline() || ancestor.is_inline_block())
+                    return ancestor;
+            }
+            VERIFY_NOT_REACHED();
+        }();
+        auto& insertion_point = insertion_parent_for_block_node(nearest_non_inline_ancestor, node);
+        if (mode == AppendOrPrepend::Prepend)
+            insertion_point.prepend_child(node);
+        else
+            insertion_point.append_child(node);
+
+        // After inserting an in-flow block-level box into a parent, mark the parent as having non-inline children.
+        if (!node.is_floating() && !node.is_absolutely_positioned())
+            insertion_point.set_children_are_inline(false);
+    }
+}
+
+RefPtr<Layout::Node> TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Selector::PseudoElement pseudo_element)
+{
+    auto& document = element.document();
+    auto& style_computer = document.style_computer();
+
+    auto pseudo_element_style = style_computer.compute_style(element, pseudo_element);
+    auto pseudo_element_content = pseudo_element_style->content();
+    auto pseudo_element_display = pseudo_element_style->display();
+    // ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.
+    // We also don't create them if they are `display: none`.
+    if (pseudo_element_display.is_none()
+        || pseudo_element_content.type == CSS::ContentData::Type::Normal
+        || pseudo_element_content.type == CSS::ContentData::Type::None)
+        return nullptr;
+
+    if (auto pseudo_element_node = DOM::Element::create_layout_node_for_display_type(document, pseudo_element_display, move(pseudo_element_style), nullptr)) {
+        pseudo_element_node->set_generated(true);
+        // FIXME: Handle images, and multiple values
+        if (pseudo_element_content.type == CSS::ContentData::Type::String) {
+            auto* text = document.heap().allocate<DOM::Text>(document.realm(), document, pseudo_element_content.data);
+            auto text_node = adopt_ref(*new TextNode(document, *text));
+            push_parent(verify_cast<NodeWithStyle>(*pseudo_element_node));
+            insert_node_into_inline_or_block_ancestor(text_node, AppendOrPrepend::Append);
+            pop_parent();
+        } else {
+            TODO();
+        }
+        return pseudo_element_node.ptr();
+    }
+
+    return nullptr;
+};
+
 void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& context)
 {
     // If the parent doesn't have a layout node, we don't need one either.
@@ -149,42 +213,12 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
     if (!layout_node)
         return;
 
-    auto insert_node_into_inline_or_block_ancestor = [this](auto& node, bool prepend = false) {
-        if (node->is_inline() && !(node->is_inline_block() && m_ancestor_stack.last().computed_values().display().is_flex_inside())) {
-            // Inlines can be inserted into the nearest ancestor.
-            auto& insertion_point = insertion_parent_for_inline_node(m_ancestor_stack.last());
-            if (prepend)
-                insertion_point.prepend_child(*node);
-            else
-                insertion_point.append_child(*node);
-            insertion_point.set_children_are_inline(true);
-        } else {
-            // Non-inlines can't be inserted into an inline parent, so find the nearest non-inline ancestor.
-            auto& nearest_non_inline_ancestor = [&]() -> Layout::NodeWithStyle& {
-                for (auto& ancestor : m_ancestor_stack.in_reverse()) {
-                    if (!ancestor.is_inline() || ancestor.is_inline_block())
-                        return ancestor;
-                }
-                VERIFY_NOT_REACHED();
-            }();
-            auto& insertion_point = insertion_parent_for_block_node(nearest_non_inline_ancestor, *node);
-            if (prepend)
-                insertion_point.prepend_child(*node);
-            else
-                insertion_point.append_child(*node);
-
-            // After inserting an in-flow block-level box into a parent, mark the parent as having non-inline children.
-            if (!node->is_floating() && !node->is_absolutely_positioned())
-                insertion_point.set_children_are_inline(false);
-        }
-    };
-
     if (!dom_node.parent_or_shadow_host()) {
         m_layout_root = layout_node;
     } else if (layout_node->is_svg_box()) {
         m_ancestor_stack.last().append_child(*layout_node);
     } else {
-        insert_node_into_inline_or_block_ancestor(layout_node);
+        insert_node_into_inline_or_block_ancestor(*layout_node, AppendOrPrepend::Append);
     }
 
     auto* shadow_root = is<DOM::Element>(dom_node) ? verify_cast<DOM::Element>(dom_node).shadow_root() : nullptr;
@@ -202,43 +236,14 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
     // Add nodes for the ::before and ::after pseudo-elements.
     if (is<DOM::Element>(dom_node)) {
         auto& element = static_cast<DOM::Element&>(dom_node);
-        auto create_pseudo_element_if_needed = [&](CSS::Selector::PseudoElement pseudo_element) -> RefPtr<Node> {
-            auto pseudo_element_style = style_computer.compute_style(element, pseudo_element);
-            auto pseudo_element_content = pseudo_element_style->content();
-            auto pseudo_element_display = pseudo_element_style->display();
-            // ::before and ::after only exist if they have content. `content: normal` computes to `none` for them.
-            // We also don't create them if they are `display: none`.
-            if (pseudo_element_display.is_none()
-                || pseudo_element_content.type == CSS::ContentData::Type::Normal
-                || pseudo_element_content.type == CSS::ContentData::Type::None)
-                return nullptr;
-
-            if (auto pseudo_element_node = DOM::Element::create_layout_node_for_display_type(document, pseudo_element_display, move(pseudo_element_style), nullptr)) {
-                pseudo_element_node->set_generated(true);
-                // FIXME: Handle images, and multiple values
-                if (pseudo_element_content.type == CSS::ContentData::Type::String) {
-                    auto* text = document.heap().allocate<DOM::Text>(document.realm(), document, pseudo_element_content.data);
-                    auto text_node = adopt_ref(*new TextNode(document, *text));
-                    push_parent(verify_cast<NodeWithStyle>(*pseudo_element_node));
-                    insert_node_into_inline_or_block_ancestor(text_node);
-                    pop_parent();
-                } else {
-                    TODO();
-                }
-                return pseudo_element_node.ptr();
-            }
-
-            return nullptr;
-        };
-
         push_parent(verify_cast<NodeWithStyle>(*layout_node));
-        if (auto before_node = create_pseudo_element_if_needed(CSS::Selector::PseudoElement::Before)) {
+        if (auto before_node = create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::Before)) {
             element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Before, before_node.ptr());
-            insert_node_into_inline_or_block_ancestor(before_node, true);
+            insert_node_into_inline_or_block_ancestor(*before_node, AppendOrPrepend::Prepend);
         }
-        if (auto after_node = create_pseudo_element_if_needed(CSS::Selector::PseudoElement::After)) {
+        if (auto after_node = create_pseudo_element_if_needed(element, CSS::Selector::PseudoElement::After)) {
             element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::After, after_node.ptr());
-            insert_node_into_inline_or_block_ancestor(after_node);
+            insert_node_into_inline_or_block_ancestor(*after_node, AppendOrPrepend::Append);
         }
         pop_parent();
     }

+ 7 - 0
Userland/Libraries/LibWeb/Layout/TreeBuilder.h

@@ -40,6 +40,13 @@ private:
     void generate_missing_child_wrappers(NodeWithStyle& root);
     void generate_missing_parents(NodeWithStyle& root);
 
+    enum class AppendOrPrepend {
+        Append,
+        Prepend,
+    };
+    void insert_node_into_inline_or_block_ancestor(Layout::Node&, AppendOrPrepend);
+    RefPtr<Layout::Node> create_pseudo_element_if_needed(DOM::Element&, CSS::Selector::PseudoElement);
+
     RefPtr<Layout::Node> m_layout_root;
     Vector<Layout::NodeWithStyle&> m_ancestor_stack;
 };