diff --git a/Libraries/LibHTML/DOM/Node.cpp b/Libraries/LibHTML/DOM/Node.cpp index b1aef1eea7..6e60448850 100644 --- a/Libraries/LibHTML/DOM/Node.cpp +++ b/Libraries/LibHTML/DOM/Node.cpp @@ -1,5 +1,11 @@ #include +#include +#include #include +#include +#include +#include +#include Node::Node(NodeType type) : m_type(type) @@ -9,3 +15,60 @@ Node::Node(NodeType type) Node::~Node() { } + +RefPtr Node::create_layout_node(const StyleResolver& resolver, const StyleProperties* parent_properties) const +{ + if (is_document()) + return adopt(*new LayoutDocument(static_cast(*this), {})); + + auto style_properties = resolver.resolve_style(static_cast(*this), parent_properties); + auto display_property = style_properties.property("display"); + String display = display_property.has_value() ? display_property.release_value()->to_string() : "inline"; + + if (is_text()) + return adopt(*new LayoutText(static_cast(*this), move(style_properties))); + if (display == "none") + return nullptr; + if (display == "block" || display == "list-item") + return adopt(*new LayoutBlock(this, move(style_properties))); + if (display == "inline") + return adopt(*new LayoutInline(*this, move(style_properties))); + + ASSERT_NOT_REACHED(); +} + + +RefPtr Node::create_layout_tree(const StyleResolver& resolver, const StyleProperties* parent_properties) const +{ + auto layout_node = create_layout_node(resolver, parent_properties); + if (!layout_node) + return nullptr; + + if (!has_children()) + return layout_node; + + Vector> layout_children; + bool have_inline_children = false; + bool have_block_children = false; + + static_cast(*this).for_each_child([&](const Node& child) { + auto layout_child = child.create_layout_tree(resolver, &layout_node->style_properties()); + if (!layout_child) + return; + if (!layout_child->is_block()) + have_inline_children = true; + if (layout_child->is_block()) + have_block_children = true; + layout_children.append(move(layout_child)); + }); + + for (auto layout_child : layout_children) + if (have_block_children && have_inline_children && !layout_child->is_block()) { + if (layout_child->is_text() && static_cast(*layout_child).text() == " ") + continue; + layout_node->inline_wrapper().append_child(*layout_child); + } else { + layout_node->append_child(*layout_child); + } + return layout_node; +} diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h index e04770f01d..c26ed8a5aa 100644 --- a/Libraries/LibHTML/DOM/Node.h +++ b/Libraries/LibHTML/DOM/Node.h @@ -13,6 +13,9 @@ enum class NodeType : unsigned { }; class ParentNode; +class LayoutNode; +class StyleResolver; +class StyleProperties; class Node : public TreeNode { public: @@ -24,6 +27,9 @@ public: bool is_document() const { return type() == NodeType::DOCUMENT_NODE; } bool is_parent_node() const { return is_element() || is_document(); } + RefPtr create_layout_node(const StyleResolver&, const StyleProperties* parent_properties) const; + RefPtr create_layout_tree(const StyleResolver&, const StyleProperties* parent_properties) const; + protected: explicit Node(NodeType); diff --git a/Libraries/LibHTML/Frame.cpp b/Libraries/LibHTML/Frame.cpp index 78005562b3..7681fa3df1 100644 --- a/Libraries/LibHTML/Frame.cpp +++ b/Libraries/LibHTML/Frame.cpp @@ -22,54 +22,12 @@ void Frame::set_document(Document* document) m_document = document; } -RefPtr Frame::generate_layout_tree() -{ - auto resolver = m_document->style_resolver(); - auto create_layout_node = [&](const Node& node) -> RefPtr { - if (node.is_document()) - return adopt(*new LayoutDocument(static_cast(node), {})); - - auto style_properties = resolver.resolve_style(static_cast(node)); - auto display_property = style_properties.property("display"); - String display = display_property.has_value() ? display_property.release_value()->to_string() : "inline"; - - if (display == "none") - return nullptr; - if (display == "block") - return adopt(*new LayoutBlock(&node, move(style_properties))); - if (display == "inline") - return adopt(*new LayoutInline(node, move(style_properties))); - - ASSERT_NOT_REACHED(); - }; - - Function(const Node&)> build_layout_tree; - build_layout_tree = [&](const Node& node) -> RefPtr { - auto layout_node = create_layout_node(node); - if (!layout_node) - return nullptr; - if (!node.has_children()) - return layout_node; - static_cast(node).for_each_child([&](const Node& child) { - auto layout_child = build_layout_tree(child); - if (!layout_child) - return; - if (layout_child->is_inline()) - layout_node->inline_wrapper().append_child(*layout_child); - else - layout_node->append_child(*layout_child); - }); - return layout_node; - }; - return build_layout_tree(*m_document); -} - void Frame::layout() { if (!m_document) return; - auto layout_root = generate_layout_tree(); + auto layout_root = m_document->create_layout_tree(m_document->style_resolver(), nullptr); layout_root->style().size().set_width(m_size.width());