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.
This commit is contained in:
Andreas Kling 2020-06-13 00:44:26 +02:00
parent fa5e8be31c
commit 384b5f15c9
Notes: sideshowbarker 2024-07-19 05:41:10 +09:00
2 changed files with 31 additions and 10 deletions

View File

@ -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);
}
}

View File

@ -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);