1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 08:38:12 +00:00

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.
This commit is contained in:
Andreas Kling 2019-06-28 21:17:34 +02:00
parent 3af59dfed1
commit ffcbe8f0de
6 changed files with 86 additions and 16 deletions

View file

@ -1,5 +1,7 @@
#include <LibHTML/CSS/StyleResolver.h> #include <LibHTML/CSS/StyleResolver.h>
#include <LibHTML/CSS/StyleSheet.h> #include <LibHTML/CSS/StyleSheet.h>
#include <LibHTML/CSS/StyledNode.h>
#include <LibHTML/DOM/Document.h>
#include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/Element.h>
#include <LibHTML/Dump.h> #include <LibHTML/Dump.h>
#include <stdio.h> #include <stdio.h>
@ -51,15 +53,19 @@ NonnullRefPtrVector<StyleRule> StyleResolver::collect_matching_rules(const Eleme
return matching_rules; return matching_rules;
} }
OwnPtr<LayoutStyle> StyleResolver::resolve_document_style(const Document& document) NonnullRefPtr<StyledNode> StyleResolver::create_styled_node(const Document& document)
{ {
UNUSED_PARAM(document); return StyledNode::create(document);
return make<LayoutStyle>();
} }
OwnPtr<LayoutStyle> StyleResolver::resolve_element_style(const Element& element) NonnullRefPtr<StyledNode> StyleResolver::create_styled_node(const Element& element)
{ {
auto style = make<LayoutStyle>(); auto style = StyledNode::create(element);
auto matching_rules = collect_matching_rules(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; return style;
} }

View file

@ -2,12 +2,13 @@
#include <AK/OwnPtr.h> #include <AK/OwnPtr.h>
#include <AK/NonnullRefPtrVector.h> #include <AK/NonnullRefPtrVector.h>
#include <LibHTML/Layout/LayoutStyle.h>
class Document; class Document;
class Element; class Element;
class ParentNode;
class StyleRule; class StyleRule;
class StyleSheet; class StyleSheet;
class StyledNode;
class StyleResolver { class StyleResolver {
public: public:
@ -19,8 +20,8 @@ public:
void add_sheet(const StyleSheet& sheet) { m_sheets.append(sheet); } void add_sheet(const StyleSheet& sheet) { m_sheets.append(sheet); }
OwnPtr<LayoutStyle> resolve_element_style(const Element&); NonnullRefPtr<StyledNode> create_styled_node(const Element&);
OwnPtr<LayoutStyle> resolve_document_style(const Document&); NonnullRefPtr<StyledNode> create_styled_node(const Document&);
NonnullRefPtrVector<StyleRule> collect_matching_rules(const Element&) const; NonnullRefPtrVector<StyleRule> collect_matching_rules(const Element&) const;

View file

@ -10,6 +10,10 @@ class Node;
class StyledNode : public TreeNode<StyledNode> { class StyledNode : public TreeNode<StyledNode> {
public: public:
static NonnullRefPtr<StyledNode> create(const Node& node)
{
return adopt(*new StyledNode(&node));
}
~StyledNode(); ~StyledNode();
const Node* node() const { return m_node; } const Node* node() const { return m_node; }
@ -28,6 +32,18 @@ public:
callback(*node); callback(*node);
} }
template<typename Callback>
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<StyleValue> value)
{
m_property_values.set(name, move(value));
}
protected: protected:
explicit StyledNode(const Node*); explicit StyledNode(const Node*);

View file

@ -1,4 +1,5 @@
#include <LibHTML/CSS/StyleSheet.h> #include <LibHTML/CSS/StyleSheet.h>
#include <LibHTML/CSS/StyledNode.h>
#include <LibHTML/DOM/Document.h> #include <LibHTML/DOM/Document.h>
#include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/Element.h>
#include <LibHTML/DOM/Text.h> #include <LibHTML/DOM/Text.h>
@ -67,6 +68,38 @@ void dump_tree(const LayoutNode& layout_node)
--indent; --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<const Element&>(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) void dump_rule(const StyleRule& rule)
{ {
printf("Rule:\n"); printf("Rule:\n");

View file

@ -4,8 +4,10 @@ class Node;
class LayoutNode; class LayoutNode;
class StyleRule; class StyleRule;
class StyleSheet; class StyleSheet;
class StyledNode;
void dump_tree(const Node&); void dump_tree(const Node&);
void dump_tree(const StyledNode&);
void dump_tree(const LayoutNode&); void dump_tree(const LayoutNode&);
void dump_sheet(const StyleSheet&); void dump_sheet(const StyleSheet&);
void dump_rule(const StyleRule&); void dump_rule(const StyleRule&);

View file

@ -3,6 +3,7 @@
#include <LibHTML/Frame.h> #include <LibHTML/Frame.h>
#include <LibHTML/Parser/CSSParser.h> #include <LibHTML/Parser/CSSParser.h>
#include <LibHTML/CSS/StyleResolver.h> #include <LibHTML/CSS/StyleResolver.h>
#include <LibHTML/CSS/StyledNode.h>
#include <LibHTML/DOM/Element.h> #include <LibHTML/DOM/Element.h>
#include <LibHTML/Parser/HTMLParser.h> #include <LibHTML/Parser/HTMLParser.h>
#include <stdio.h> #include <stdio.h>
@ -28,18 +29,29 @@ int main(int argc, char** argv)
StyleResolver resolver(*doc); StyleResolver resolver(*doc);
resolver.add_sheet(*sheet); resolver.add_sheet(*sheet);
auto doc_style = resolver.resolve_document_style(*doc); Function<RefPtr<StyledNode>(const Node&, StyledNode*)> resolve_style = [&](const Node& node, StyledNode* parent_styled_node) -> RefPtr<StyledNode> {
auto styled_node = [&]() -> RefPtr<StyledNode> {
Function<void(const ParentNode&)> resolve_style = [&](const ParentNode& node) { if (node.is_element())
node.for_each_child([&](const Node& child) { return resolver.create_styled_node(static_cast<const Element&>(node));
if (node.is_document())
return resolver.create_styled_node(static_cast<const Document&>(node));
return nullptr;
}();
if (!styled_node)
return nullptr;
if (parent_styled_node)
parent_styled_node->append_child(*styled_node);
static_cast<const ParentNode&>(node).for_each_child([&](const Node& child) {
if (!child.is_element()) if (!child.is_element())
return; return;
auto style = resolver.resolve_element_style(static_cast<const Element&>(node)); auto styled_child_node = resolve_style(static_cast<const Element&>(child), styled_node.ptr());
printf("Resolved LayoutStyle{%p} for Element{%p}\n", style.ptr(), &node); printf("Created StyledNode{%p} for Element{%p}\n", styled_child_node.ptr(), &node);
resolve_style(static_cast<const Element&>(child));
}); });
return styled_node;
}; };
resolve_style(*doc); auto styled_root = resolve_style(*doc, nullptr);
dump_tree(*styled_root);
doc->build_layout_tree(); doc->build_layout_tree();
ASSERT(doc->layout_node()); ASSERT(doc->layout_node());