diff options
author | Sergey Bugaev <bugaevc@gmail.com> | 2019-09-25 12:17:29 +0300 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-09-28 18:29:42 +0200 |
commit | 599edba7a34533e02aaf4218cc77add480674ea3 (patch) | |
tree | 578db126e7825d6b20d2664a253604078cc41a92 /Libraries | |
parent | 841ae4439234abde6c186f021845dd5448586ab2 (diff) | |
download | serenity-599edba7a34533e02aaf4218cc77add480674ea3.zip |
LibHTML: Move layout tree building to Node
This also fixes another bug with inline wrappers. Namely,
we should only add inline wrappers if a block node has
both non-block (inline or text) and block children.
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibHTML/DOM/Node.cpp | 63 | ||||
-rw-r--r-- | Libraries/LibHTML/DOM/Node.h | 6 | ||||
-rw-r--r-- | Libraries/LibHTML/Frame.cpp | 44 |
3 files changed, 70 insertions, 43 deletions
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 <LibHTML/DOM/Node.h> +#include <LibHTML/DOM/Element.h> +#include <LibHTML/CSS/StyleResolver.h> #include <LibHTML/Layout/LayoutNode.h> +#include <LibHTML/Layout/LayoutBlock.h> +#include <LibHTML/Layout/LayoutDocument.h> +#include <LibHTML/Layout/LayoutInline.h> +#include <LibHTML/Layout/LayoutText.h> Node::Node(NodeType type) : m_type(type) @@ -9,3 +15,60 @@ Node::Node(NodeType type) Node::~Node() { } + +RefPtr<LayoutNode> Node::create_layout_node(const StyleResolver& resolver, const StyleProperties* parent_properties) const +{ + if (is_document()) + return adopt(*new LayoutDocument(static_cast<const Document&>(*this), {})); + + auto style_properties = resolver.resolve_style(static_cast<const Element&>(*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<const Text&>(*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<LayoutNode> 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<RefPtr<LayoutNode>> layout_children; + bool have_inline_children = false; + bool have_block_children = false; + + static_cast<const ParentNode&>(*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<const LayoutText&>(*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<Node> { 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<LayoutNode> create_layout_node(const StyleResolver&, const StyleProperties* parent_properties) const; + RefPtr<LayoutNode> 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<LayoutNode> Frame::generate_layout_tree() -{ - auto resolver = m_document->style_resolver(); - auto create_layout_node = [&](const Node& node) -> RefPtr<LayoutNode> { - if (node.is_document()) - return adopt(*new LayoutDocument(static_cast<const Document&>(node), {})); - - auto style_properties = resolver.resolve_style(static_cast<const Element&>(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<RefPtr<LayoutNode>(const Node&)> build_layout_tree; - build_layout_tree = [&](const Node& node) -> RefPtr<LayoutNode> { - auto layout_node = create_layout_node(node); - if (!layout_node) - return nullptr; - if (!node.has_children()) - return layout_node; - static_cast<const ParentNode&>(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()); |