diff --git a/LibHTML/CSS/StyleResolver.cpp b/LibHTML/CSS/StyleResolver.cpp index 07e9e636d9..15aef1ba51 100644 --- a/LibHTML/CSS/StyleResolver.cpp +++ b/LibHTML/CSS/StyleResolver.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include StyleResolver::StyleResolver(Document& document) : m_document(document) @@ -10,14 +13,53 @@ StyleResolver::~StyleResolver() { } +static bool matches(const Selector& selector, const Element& element) +{ + // FIXME: Support compound selectors. + ASSERT(selector.components().size() == 1); + + auto& component = selector.components().first(); + switch (component.type) { + case Selector::Component::Type::Id: + return component.value == element.attribute("id"); + case Selector::Component::Type::Class: + return element.has_class(component.value); + case Selector::Component::Type::TagName: + return component.value == element.tag_name(); + default: + ASSERT_NOT_REACHED(); + } +} + +NonnullRefPtrVector StyleResolver::collect_matching_rules(const Element& element) const +{ + NonnullRefPtrVector matching_rules; + for (auto& sheet : m_sheets) { + for (auto& rule : sheet.rules()) { + for (auto& selector : rule.selectors()) { + if (matches(selector, element)) { + matching_rules.append(rule); + break; + } + } + } + } + printf("Rules matching Element{%p}\n", &element); + for (auto& rule : matching_rules) { + dump_rule(rule); + } + return matching_rules; +} + OwnPtr StyleResolver::resolve_document_style(const Document& document) { UNUSED_PARAM(document); - return nullptr; + return make(); } OwnPtr StyleResolver::resolve_element_style(const Element& element) { - UNUSED_PARAM(element); - return nullptr; + auto style = make(); + auto matching_rules = collect_matching_rules(element); + return style; } diff --git a/LibHTML/CSS/StyleResolver.h b/LibHTML/CSS/StyleResolver.h index 2875d81700..a11133e0f9 100644 --- a/LibHTML/CSS/StyleResolver.h +++ b/LibHTML/CSS/StyleResolver.h @@ -6,6 +6,7 @@ class Document; class Element; +class StyleRule; class StyleSheet; class StyleResolver { @@ -21,6 +22,9 @@ public: OwnPtr resolve_element_style(const Element&); OwnPtr resolve_document_style(const Document&); + NonnullRefPtrVector collect_matching_rules(const Element&) const; + + private: Document& m_document; diff --git a/LibHTML/DOM/Element.cpp b/LibHTML/DOM/Element.cpp index e291fc3dd0..7808170a60 100644 --- a/LibHTML/DOM/Element.cpp +++ b/LibHTML/DOM/Element.cpp @@ -50,6 +50,19 @@ void Element::set_attributes(Vector&& attributes) m_attributes = move(attributes); } +bool Element::has_class(const StringView& class_name) const +{ + auto value = attribute("class"); + if (value.is_empty()) + return false; + auto parts = value.split_view(' '); + for (auto& part : parts) { + if (part == class_name) + return true; + } + return false; +} + RefPtr Element::create_layout_node() { if (m_tag_name == "html") diff --git a/LibHTML/DOM/Element.h b/LibHTML/DOM/Element.h index 1331d20c7e..f3133656ca 100644 --- a/LibHTML/DOM/Element.h +++ b/LibHTML/DOM/Element.h @@ -40,6 +40,8 @@ public: callback(attribute.name(), attribute.value()); } + bool has_class(const StringView&) const; + virtual RefPtr create_layout_node() override; private: diff --git a/LibHTML/Dump.cpp b/LibHTML/Dump.cpp index e9c2a2b313..4d9632509f 100644 --- a/LibHTML/Dump.cpp +++ b/LibHTML/Dump.cpp @@ -67,36 +67,41 @@ void dump_tree(const LayoutNode& layout_node) --indent; } +void dump_rule(const StyleRule& rule) +{ + printf("Rule:\n"); + for (auto& selector : rule.selectors()) { + printf(" Selector:\n"); + for (auto& component : selector.components()) { + const char* type_description = "Unknown"; + switch (component.type) { + case Selector::Component::Type::Invalid: + type_description = "Invalid"; + break; + case Selector::Component::Type::Id: + type_description = "Id"; + break; + case Selector::Component::Type::Class: + type_description = "Class"; + break; + case Selector::Component::Type::TagName: + type_description = "TagName"; + break; + } + printf(" %s:%s\n", type_description, component.value.characters()); + } + } + printf(" Declarations:\n"); + for (auto& declaration : rule.declarations()) { + printf(" '%s': '%s'\n", declaration.property_name().characters(), declaration.value().to_string().characters()); + } +} + void dump_sheet(const StyleSheet& sheet) { printf("StyleSheet{%p}: %d rule(s)\n", &sheet, sheet.rules().size()); for (auto& rule : sheet.rules()) { - printf("Rule:\n"); - for (auto& selector : rule.selectors()) { - printf(" Selector:\n"); - for (auto& component : selector.components()) { - const char* type_description = "Unknown"; - switch (component.type) { - case Selector::Component::Type::Invalid: - type_description = "Invalid"; - break; - case Selector::Component::Type::Id: - type_description = "Id"; - break; - case Selector::Component::Type::Class: - type_description = "Class"; - break; - case Selector::Component::Type::TagName: - type_description = "TagName"; - break; - } - printf(" %s:%s", type_description, component.value.characters()); - } - } - printf(" Declarations:\n"); - rule.for_each_declaration([](auto& declaration) { - printf(" '%s': '%s'\n", declaration.property_name().characters(), declaration.value().to_string().characters()); - }); + dump_rule(rule); } } diff --git a/LibHTML/Dump.h b/LibHTML/Dump.h index b7049f861a..546e556ba7 100644 --- a/LibHTML/Dump.h +++ b/LibHTML/Dump.h @@ -2,8 +2,10 @@ class Node; class LayoutNode; +class StyleRule; class StyleSheet; void dump_tree(const Node&); 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 c5ba6d73fd..07eed25dc1 100644 --- a/LibHTML/test.cpp +++ b/LibHTML/test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -29,6 +30,17 @@ int main(int argc, char** argv) auto doc_style = resolver.resolve_document_style(*doc); + Function resolve_style = [&](const ParentNode& node) { + 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)); + }); + }; + resolve_style(*doc); + doc->build_layout_tree(); ASSERT(doc->layout_node());