summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-06-13 00:44:26 +0200
committerAndreas Kling <kling@serenityos.org>2020-06-13 00:44:26 +0200
commit384b5f15c943ad0b19fba2878ba3a8f7879ca413 (patch)
tree4930ae9a2e0e45d394728cf4382580252b31e2ce
parentfa5e8be31cb73a33afbfd67b6d1bbb04a18fbc4d (diff)
downloadserenity-384b5f15c943ad0b19fba2878ba3a8f7879ca413.zip
LibWeb: Sort matched style rules by specificity, document order
If two rules have equal specificity, they should be applied in the order in which we encountered them.
-rw-r--r--Libraries/LibWeb/CSS/StyleResolver.cpp32
-rw-r--r--Libraries/LibWeb/CSS/StyleResolver.h9
2 files changed, 31 insertions, 10 deletions
diff --git a/Libraries/LibWeb/CSS/StyleResolver.cpp b/Libraries/LibWeb/CSS/StyleResolver.cpp
index ab6bd25cb8..80f0e8570f 100644
--- a/Libraries/LibWeb/CSS/StyleResolver.cpp
+++ b/Libraries/LibWeb/CSS/StyleResolver.cpp
@@ -66,19 +66,25 @@ void StyleResolver::for_each_stylesheet(Callback callback) const
}
}
-NonnullRefPtrVector<StyleRule> StyleResolver::collect_matching_rules(const Element& element) const
+Vector<MatchingRule> StyleResolver::collect_matching_rules(const Element& element) const
{
- NonnullRefPtrVector<StyleRule> matching_rules;
+ Vector<MatchingRule> matching_rules;
+ size_t style_sheet_index = 0;
for_each_stylesheet([&](auto& sheet) {
+ size_t rule_index = 0;
for (auto& rule : sheet.rules()) {
+ size_t selector_index = 0;
for (auto& selector : rule.selectors()) {
if (SelectorEngine::matches(selector, element)) {
- matching_rules.append(rule);
+ matching_rules.append({ rule, style_sheet_index, rule_index, selector_index });
break;
}
+ ++selector_index;
}
+ ++rule_index;
}
+ ++style_sheet_index;
});
#ifdef HTML_DEBUG
@@ -484,14 +490,22 @@ NonnullRefPtr<StyleProperties> StyleResolver::resolve_style(const Element& eleme
auto matching_rules = collect_matching_rules(element);
- // FIXME: We need to look at the specificity of the matching *selector*, not just the matched *rule*!
- // FIXME: It's really awkward that NonnullRefPtrVector cannot be quick_sort()'ed
- quick_sort(reinterpret_cast<Vector<NonnullRefPtr<StyleRule>>&>(matching_rules), [&](auto& a, auto& b) {
- return a->selectors().first().specificity() < b->selectors().first().specificity();
+ quick_sort(matching_rules, [&](MatchingRule& a, MatchingRule& b) {
+ auto& a_selector = a.rule->selectors()[a.selector_index];
+ auto& b_selector = b.rule->selectors()[b.selector_index];
+ if (a_selector.specificity() < b_selector.specificity())
+ return true;
+ if (!(a_selector.specificity() == b_selector.specificity()))
+ return false;
+ if (a.style_sheet_index < b.style_sheet_index)
+ return true;
+ if (a.style_sheet_index > b.style_sheet_index)
+ return false;
+ return a.rule_index < b.rule_index;
});
- for (auto& rule : matching_rules) {
- for (auto& property : rule.declaration().properties()) {
+ for (auto& match : matching_rules) {
+ for (auto& property : match.rule->declaration().properties()) {
set_property_expanding_shorthands(style, property.property_id, property.value, m_document);
}
}
diff --git a/Libraries/LibWeb/CSS/StyleResolver.h b/Libraries/LibWeb/CSS/StyleResolver.h
index 95e691ed7f..54fa2fa763 100644
--- a/Libraries/LibWeb/CSS/StyleResolver.h
+++ b/Libraries/LibWeb/CSS/StyleResolver.h
@@ -38,6 +38,13 @@ class ParentNode;
class StyleRule;
class StyleSheet;
+struct MatchingRule {
+ RefPtr<StyleRule> rule;
+ size_t style_sheet_index { 0 };
+ size_t rule_index { 0 };
+ size_t selector_index { 0 };
+};
+
class StyleResolver {
public:
explicit StyleResolver(Document&);
@@ -48,7 +55,7 @@ public:
NonnullRefPtr<StyleProperties> resolve_style(const Element&, const StyleProperties* parent_style) const;
- NonnullRefPtrVector<StyleRule> collect_matching_rules(const Element&) const;
+ Vector<MatchingRule> collect_matching_rules(const Element&) const;
static bool is_inherited_property(CSS::PropertyID);