From ffcbe8f0de0300c94fa940024edeea66b2eeced3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 28 Jun 2019 21:17:34 +0200 Subject: [PATCH] LibHTML: Start building the style tree. Walk the DOM and construct a parallel style tree that points back to the DOM and has the relevant CSS property values hanging off of them. The values are picked based on naive selector matching. There's no cascade or specificity taken into account yet. --- LibHTML/CSS/StyleResolver.cpp | 16 +++++++++++----- LibHTML/CSS/StyleResolver.h | 7 ++++--- LibHTML/CSS/StyledNode.h | 16 ++++++++++++++++ LibHTML/Dump.cpp | 33 +++++++++++++++++++++++++++++++++ LibHTML/Dump.h | 2 ++ LibHTML/test.cpp | 28 ++++++++++++++++++++-------- 6 files changed, 86 insertions(+), 16 deletions(-) diff --git a/LibHTML/CSS/StyleResolver.cpp b/LibHTML/CSS/StyleResolver.cpp index 15aef1ba51..47c28e8580 100644 --- a/LibHTML/CSS/StyleResolver.cpp +++ b/LibHTML/CSS/StyleResolver.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include #include @@ -51,15 +53,19 @@ NonnullRefPtrVector StyleResolver::collect_matching_rules(const Eleme return matching_rules; } -OwnPtr StyleResolver::resolve_document_style(const Document& document) +NonnullRefPtr StyleResolver::create_styled_node(const Document& document) { - UNUSED_PARAM(document); - return make(); + return StyledNode::create(document); } -OwnPtr StyleResolver::resolve_element_style(const Element& element) +NonnullRefPtr StyleResolver::create_styled_node(const Element& element) { - auto style = make(); + auto style = StyledNode::create(element); auto matching_rules = collect_matching_rules(element); + for (auto& rule : matching_rules) { + for (auto& declaration : rule.declarations()) { + style->set_property(declaration.property_name(), declaration.value()); + } + } return style; } diff --git a/LibHTML/CSS/StyleResolver.h b/LibHTML/CSS/StyleResolver.h index a11133e0f9..eec7042b29 100644 --- a/LibHTML/CSS/StyleResolver.h +++ b/LibHTML/CSS/StyleResolver.h @@ -2,12 +2,13 @@ #include #include -#include class Document; class Element; +class ParentNode; class StyleRule; class StyleSheet; +class StyledNode; class StyleResolver { public: @@ -19,8 +20,8 @@ public: void add_sheet(const StyleSheet& sheet) { m_sheets.append(sheet); } - OwnPtr resolve_element_style(const Element&); - OwnPtr resolve_document_style(const Document&); + NonnullRefPtr create_styled_node(const Element&); + NonnullRefPtr create_styled_node(const Document&); NonnullRefPtrVector collect_matching_rules(const Element&) const; diff --git a/LibHTML/CSS/StyledNode.h b/LibHTML/CSS/StyledNode.h index eaf171e570..61d43b5156 100644 --- a/LibHTML/CSS/StyledNode.h +++ b/LibHTML/CSS/StyledNode.h @@ -10,6 +10,10 @@ class Node; class StyledNode : public TreeNode { public: + static NonnullRefPtr create(const Node& node) + { + return adopt(*new StyledNode(&node)); + } ~StyledNode(); const Node* node() const { return m_node; } @@ -28,6 +32,18 @@ public: callback(*node); } + template + inline void for_each_property(Callback callback) const + { + for (auto& it : m_property_values) + callback(it.key, *it.value); + } + + void set_property(const String& name, NonnullRefPtr value) + { + m_property_values.set(name, move(value)); + } + protected: explicit StyledNode(const Node*); diff --git a/LibHTML/Dump.cpp b/LibHTML/Dump.cpp index 4d9632509f..477b8aa55a 100644 --- a/LibHTML/Dump.cpp +++ b/LibHTML/Dump.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -67,6 +68,38 @@ void dump_tree(const LayoutNode& layout_node) --indent; } +void dump_tree(const StyledNode& styled_node) +{ + static int indent = 0; + for (int i = 0; i < indent; ++i) + printf(" "); + + String tag_name; + auto& node = *styled_node.node(); + if (node.is_text()) + tag_name = "#text"; + else if (node.is_document()) + tag_name = "#document"; + else if (node.is_element()) + tag_name = static_cast(node).tag_name(); + else + tag_name = "???"; + + printf("%s", tag_name.characters()); + printf("\n"); + + styled_node.for_each_property([&](auto& key, auto& value) { + for (int i = 0; i < indent; ++i) + printf(" "); + printf(" (%s: %s)\n", key.characters(), value.to_string().characters()); + }); + ++indent; + styled_node.for_each_child([](auto& child) { + dump_tree(child); + }); + --indent; +} + void dump_rule(const StyleRule& rule) { printf("Rule:\n"); diff --git a/LibHTML/Dump.h b/LibHTML/Dump.h index 546e556ba7..c7c0953e6d 100644 --- a/LibHTML/Dump.h +++ b/LibHTML/Dump.h @@ -4,8 +4,10 @@ class Node; class LayoutNode; class StyleRule; class StyleSheet; +class StyledNode; void dump_tree(const Node&); +void dump_tree(const StyledNode&); void dump_tree(const LayoutNode&); void dump_sheet(const StyleSheet&); void dump_rule(const StyleRule&); diff --git a/LibHTML/test.cpp b/LibHTML/test.cpp index 07eed25dc1..e3d23837d8 100644 --- a/LibHTML/test.cpp +++ b/LibHTML/test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -28,18 +29,29 @@ int main(int argc, char** argv) StyleResolver resolver(*doc); resolver.add_sheet(*sheet); - auto doc_style = resolver.resolve_document_style(*doc); - - Function resolve_style = [&](const ParentNode& node) { - node.for_each_child([&](const Node& child) { + Function(const Node&, StyledNode*)> resolve_style = [&](const Node& node, StyledNode* parent_styled_node) -> RefPtr { + auto styled_node = [&]() -> RefPtr { + if (node.is_element()) + return resolver.create_styled_node(static_cast(node)); + if (node.is_document()) + return resolver.create_styled_node(static_cast(node)); + return nullptr; + }(); + if (!styled_node) + return nullptr; + if (parent_styled_node) + parent_styled_node->append_child(*styled_node); + static_cast(node).for_each_child([&](const Node& child) { if (!child.is_element()) return; - auto style = resolver.resolve_element_style(static_cast(node)); - printf("Resolved LayoutStyle{%p} for Element{%p}\n", style.ptr(), &node); - resolve_style(static_cast(child)); + auto styled_child_node = resolve_style(static_cast(child), styled_node.ptr()); + printf("Created StyledNode{%p} for Element{%p}\n", styled_child_node.ptr(), &node); }); + return styled_node; }; - resolve_style(*doc); + auto styled_root = resolve_style(*doc, nullptr); + + dump_tree(*styled_root); doc->build_layout_tree(); ASSERT(doc->layout_node());