LibWeb: Evaluate @media rules

We now evaluate the conditions of `@media` rules at the same point in
the HTML event loop as evaluation of `MediaQueryList`s. This is not
strictly to spec, but since the spec doesn't actually say when to do
this, it seems to make the most sense. In any case, it works! :^)
This commit is contained in:
Sam Atkins 2021-10-08 20:21:46 +01:00 committed by Andreas Kling
parent 57a25139a5
commit 5098cd22a4
Notes: sideshowbarker 2024-07-18 02:54:51 +09:00
8 changed files with 47 additions and 2 deletions

View file

@ -22,6 +22,7 @@ public:
~CSSGroupingRule();
CSSRuleList const& css_rules() const { return m_rules; }
CSSRuleList& css_rules() { return m_rules; }
size_t insert_rule(StringView const& rule, size_t index = 0);
void delete_rule(size_t index);

View file

@ -30,11 +30,12 @@ public:
virtual String condition_text() const override;
virtual void set_condition_text(String) override;
// FIXME: We need to evaluate() the query before matches() will work!
virtual bool condition_matches() const override { return m_media->matches(); }
NonnullRefPtr<MediaList> const& media() const { return m_media; }
bool evaluate(DOM::Window const& window) { return m_media->evaluate(window); }
private:
explicit CSSMediaRule(NonnullRefPtr<MediaList>&&, NonnullRefPtrVector<CSSRule>&&);

View file

@ -126,4 +126,34 @@ bool CSSRuleList::for_first_not_loaded_import_rule(Function<void(CSSImportRule&)
return false;
}
void CSSRuleList::evaluate_media_queries(DOM::Window const& window)
{
for (auto& rule : m_rules) {
switch (rule.type()) {
case CSSRule::Type::Style:
break;
case CSSRule::Type::Import: {
auto& import_rule = verify_cast<CSSImportRule>(rule);
if (import_rule.has_import_result())
import_rule.loaded_style_sheet()->evaluate_media_queries(window);
break;
}
case CSSRule::Type::Media: {
auto& media_rule = verify_cast<CSSMediaRule>(rule);
if (media_rule.evaluate(window))
media_rule.css_rules().evaluate_media_queries(window);
break;
}
case CSSRule::Type::Supports: {
auto& supports_rule = verify_cast<CSSSupportsRule>(rule);
if (supports_rule.condition_matches())
supports_rule.css_rules().evaluate_media_queries(window);
break;
}
case CSSRule::Type::__Count:
VERIFY_NOT_REACHED();
}
}
}
}

View file

@ -53,6 +53,7 @@ public:
void for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const;
bool for_first_not_loaded_import_rule(Function<void(CSSImportRule&)> const& callback);
void evaluate_media_queries(DOM::Window const&);
private:
explicit CSSRuleList(NonnullRefPtrVector<CSSRule>&&);

View file

@ -67,4 +67,9 @@ bool CSSStyleSheet::for_first_not_loaded_import_rule(Function<void(CSSImportRule
return m_rules->for_first_not_loaded_import_rule(callback);
}
void CSSStyleSheet::evaluate_media_queries(DOM::Window const& window)
{
m_rules->evaluate_media_queries(window);
}
}

View file

@ -46,6 +46,7 @@ public:
void for_each_effective_style_rule(Function<void(CSSStyleRule const&)> const& callback) const;
bool for_first_not_loaded_import_rule(Function<void(CSSImportRule&)> const& callback);
void evaluate_media_queries(DOM::Window const&);
private:
explicit CSSStyleSheet(NonnullRefPtrVector<CSSRule>);

View file

@ -28,7 +28,8 @@ public:
void add_sheet(NonnullRefPtr<CSSStyleSheet>);
void remove_sheet(CSSStyleSheet&);
const NonnullRefPtrVector<CSSStyleSheet>& sheets() const { return m_sheets; }
NonnullRefPtrVector<CSSStyleSheet> const& sheets() const { return m_sheets; }
NonnullRefPtrVector<CSSStyleSheet>& sheets() { return m_sheets; }
RefPtr<CSSStyleSheet> item(size_t index) const
{

View file

@ -1156,6 +1156,11 @@ void Document::evaluate_media_queries_and_report_changes()
media_query_list->dispatch_event(event);
}
}
// Also not in the spec, but this is as good a place as any to evaluate @media rules!
for (auto& style_sheet : style_sheets().sheets()) {
style_sheet.evaluate_media_queries(window());
}
}
}