mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
LibWeb/CSS: Support media queries in import at-rules
This commit is contained in:
parent
c1fe912bf9
commit
ac19b0cda8
Notes:
github-actions[bot]
2025-04-02 13:56:49 +00:00
Author: https://github.com/tcl3
Commit: ac19b0cda8
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4183
Reviewed-by: https://github.com/AtkinsSJ ✅
7 changed files with 51 additions and 15 deletions
|
@ -23,17 +23,18 @@ namespace Web::CSS {
|
||||||
|
|
||||||
GC_DEFINE_ALLOCATOR(CSSImportRule);
|
GC_DEFINE_ALLOCATOR(CSSImportRule);
|
||||||
|
|
||||||
GC::Ref<CSSImportRule> CSSImportRule::create(URL::URL url, DOM::Document& document, RefPtr<Supports> supports)
|
GC::Ref<CSSImportRule> CSSImportRule::create(URL::URL url, DOM::Document& document, RefPtr<Supports> supports, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
|
||||||
{
|
{
|
||||||
auto& realm = document.realm();
|
auto& realm = document.realm();
|
||||||
return realm.create<CSSImportRule>(move(url), document, supports);
|
return realm.create<CSSImportRule>(move(url), document, supports, move(media_query_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
CSSImportRule::CSSImportRule(URL::URL url, DOM::Document& document, RefPtr<Supports> supports)
|
CSSImportRule::CSSImportRule(URL::URL url, DOM::Document& document, RefPtr<Supports> supports, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
|
||||||
: CSSRule(document.realm(), Type::Import)
|
: CSSRule(document.realm(), Type::Import)
|
||||||
, m_url(move(url))
|
, m_url(move(url))
|
||||||
, m_document(document)
|
, m_document(document)
|
||||||
, m_supports(supports)
|
, m_supports(supports)
|
||||||
|
, m_media_query_list(move(media_query_list))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +77,9 @@ String CSSImportRule::serialized() const
|
||||||
if (m_supports)
|
if (m_supports)
|
||||||
builder.appendff(" supports({})", m_supports->to_string());
|
builder.appendff(" supports({})", m_supports->to_string());
|
||||||
|
|
||||||
// FIXME: 3. If the rule’s associated media list is not empty, a single SPACE (U+0020) followed by the result of performing serialize a media query list on the media list.
|
// 3. If the rule’s associated media list is not empty, a single SPACE (U+0020) followed by the result of performing serialize a media query list on the media list.
|
||||||
|
if (!m_media_query_list.is_empty())
|
||||||
|
builder.appendff(" {}", serialize_a_media_query_list(m_media_query_list));
|
||||||
|
|
||||||
// 4. The string ";", i.e., SEMICOLON (U+003B).
|
// 4. The string ";", i.e., SEMICOLON (U+003B).
|
||||||
builder.append(';');
|
builder.append(';');
|
||||||
|
@ -148,7 +151,7 @@ void CSSImportRule::fetch()
|
||||||
}
|
}
|
||||||
auto decoded = decoded_or_error.release_value();
|
auto decoded = decoded_or_error.release_value();
|
||||||
|
|
||||||
auto* imported_style_sheet = parse_css_stylesheet(Parser::ParsingParams(*strong_this->m_document, strong_this->url()), decoded, strong_this->url());
|
auto* imported_style_sheet = parse_css_stylesheet(Parser::ParsingParams(*strong_this->m_document, strong_this->url()), decoded, strong_this->url(), strong_this->m_media_query_list);
|
||||||
|
|
||||||
// 5. Set importedStylesheet’s origin-clean flag to parentStylesheet’s origin-clean flag.
|
// 5. Set importedStylesheet’s origin-clean flag to parentStylesheet’s origin-clean flag.
|
||||||
imported_style_sheet->set_origin_clean(parent_style_sheet->is_origin_clean());
|
imported_style_sheet->set_origin_clean(parent_style_sheet->is_origin_clean());
|
||||||
|
|
|
@ -21,7 +21,7 @@ class CSSImportRule final
|
||||||
GC_DECLARE_ALLOCATOR(CSSImportRule);
|
GC_DECLARE_ALLOCATOR(CSSImportRule);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] static GC::Ref<CSSImportRule> create(URL::URL, DOM::Document&, RefPtr<Supports>);
|
[[nodiscard]] static GC::Ref<CSSImportRule> create(URL::URL, DOM::Document&, RefPtr<Supports>, Vector<NonnullRefPtr<MediaQuery>>);
|
||||||
|
|
||||||
virtual ~CSSImportRule() = default;
|
virtual ~CSSImportRule() = default;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public:
|
||||||
Optional<String> supports_text() const;
|
Optional<String> supports_text() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSSImportRule(URL::URL, DOM::Document&, RefPtr<Supports>);
|
CSSImportRule(URL::URL, DOM::Document&, RefPtr<Supports>, Vector<NonnullRefPtr<MediaQuery>>);
|
||||||
|
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
@ -51,6 +51,7 @@ private:
|
||||||
URL::URL m_url;
|
URL::URL m_url;
|
||||||
GC::Ptr<DOM::Document> m_document;
|
GC::Ptr<DOM::Document> m_document;
|
||||||
RefPtr<Supports> m_supports;
|
RefPtr<Supports> m_supports;
|
||||||
|
Vector<NonnullRefPtr<MediaQuery>> m_media_query_list;
|
||||||
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
GC::Ptr<CSSStyleSheet> m_style_sheet;
|
||||||
Optional<DOM::DocumentLoadEventDelayer> m_document_load_event_delayer;
|
Optional<DOM::DocumentLoadEventDelayer> m_document_load_event_delayer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,7 +42,7 @@ GC::Ref<JS::Realm> internal_css_realm()
|
||||||
return *realm;
|
return *realm;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional<URL::URL> location)
|
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& context, StringView css, Optional<URL::URL> location, Vector<NonnullRefPtr<CSS::MediaQuery>> media_query_list)
|
||||||
{
|
{
|
||||||
if (css.is_empty()) {
|
if (css.is_empty()) {
|
||||||
auto rule_list = CSS::CSSRuleList::create_empty(*context.realm);
|
auto rule_list = CSS::CSSRuleList::create_empty(*context.realm);
|
||||||
|
@ -51,7 +51,7 @@ CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const& conte
|
||||||
style_sheet->set_source_text({});
|
style_sheet->set_source_text({});
|
||||||
return style_sheet;
|
return style_sheet;
|
||||||
}
|
}
|
||||||
auto* style_sheet = CSS::Parser::Parser::create(context, css).parse_as_css_stylesheet(location);
|
auto* style_sheet = CSS::Parser::Parser::create(context, css).parse_as_css_stylesheet(location, move(media_query_list));
|
||||||
// FIXME: Avoid this copy
|
// FIXME: Avoid this copy
|
||||||
style_sheet->set_source_text(MUST(String::from_utf8(css)));
|
style_sheet->set_source_text(MUST(String::from_utf8(css)));
|
||||||
return style_sheet;
|
return style_sheet;
|
||||||
|
|
|
@ -119,7 +119,7 @@ Vector<Rule> Parser::parse_a_stylesheets_contents(TokenStream<T>& input)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-syntax/#parse-a-css-stylesheet
|
// https://drafts.csswg.org/css-syntax/#parse-a-css-stylesheet
|
||||||
CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location)
|
CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location, Vector<NonnullRefPtr<MediaQuery>> media_query_list)
|
||||||
{
|
{
|
||||||
// To parse a CSS stylesheet, first parse a stylesheet.
|
// To parse a CSS stylesheet, first parse a stylesheet.
|
||||||
auto const& style_sheet = parse_a_stylesheet(m_token_stream, {});
|
auto const& style_sheet = parse_a_stylesheet(m_token_stream, {});
|
||||||
|
@ -138,7 +138,7 @@ CSSStyleSheet* Parser::parse_as_css_stylesheet(Optional<URL::URL> location)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rule_list = CSSRuleList::create(realm(), rules);
|
auto rule_list = CSSRuleList::create(realm(), rules);
|
||||||
auto media_list = MediaList::create(realm(), {});
|
auto media_list = MediaList::create(realm(), move(media_query_list));
|
||||||
return CSSStyleSheet::create(realm(), rule_list, media_list, move(location));
|
return CSSStyleSheet::create(realm(), rule_list, media_list, move(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class Parser {
|
||||||
public:
|
public:
|
||||||
static Parser create(ParsingParams const&, StringView input, StringView encoding = "utf-8"sv);
|
static Parser create(ParsingParams const&, StringView input, StringView encoding = "utf-8"sv);
|
||||||
|
|
||||||
CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location);
|
CSSStyleSheet* parse_as_css_stylesheet(Optional<URL::URL> location, Vector<NonnullRefPtr<MediaQuery>> media_query_list = {});
|
||||||
|
|
||||||
struct PropertiesAndCustomProperties {
|
struct PropertiesAndCustomProperties {
|
||||||
Vector<StyleProperty> properties;
|
Vector<StyleProperty> properties;
|
||||||
|
@ -512,7 +512,7 @@ private:
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
||||||
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const&, StringView, Optional<URL::URL> location = {});
|
CSS::CSSStyleSheet* parse_css_stylesheet(CSS::Parser::ParsingParams const&, StringView, Optional<URL::URL> location = {}, Vector<NonnullRefPtr<CSS::MediaQuery>> = {});
|
||||||
CSS::Parser::Parser::PropertiesAndCustomProperties parse_css_style_attribute(CSS::Parser::ParsingParams const&, StringView);
|
CSS::Parser::Parser::PropertiesAndCustomProperties parse_css_style_attribute(CSS::Parser::ParsingParams const&, StringView);
|
||||||
RefPtr<CSS::CSSStyleValue> parse_css_value(CSS::Parser::ParsingParams const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
|
RefPtr<CSS::CSSStyleValue> parse_css_value(CSS::Parser::ParsingParams const&, StringView, CSS::PropertyID property_id = CSS::PropertyID::Invalid);
|
||||||
Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingParams const&, StringView);
|
Optional<CSS::SelectorList> parse_selector(CSS::Parser::ParsingParams const&, StringView);
|
||||||
|
|
|
@ -180,7 +180,7 @@ GC::Ptr<CSSImportRule> Parser::convert_to_import_rule(AtRule const& rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Implement media query support.
|
auto media_query_list = parse_a_media_query_list(tokens);
|
||||||
|
|
||||||
if (tokens.has_next_token()) {
|
if (tokens.has_next_token()) {
|
||||||
if constexpr (CSS_PARSER_DEBUG) {
|
if constexpr (CSS_PARSER_DEBUG) {
|
||||||
|
@ -190,7 +190,7 @@ GC::Ptr<CSSImportRule> Parser::convert_to_import_rule(AtRule const& rule)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSSImportRule::create(url.value(), const_cast<DOM::Document&>(*document()), supports);
|
return CSSImportRule::create(url.value(), const_cast<DOM::Document&>(*document()), supports, move(media_query_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<FlyString> Parser::parse_layer_name(TokenStream<ComponentValue>& tokens, AllowBlankLayerName allow_blank_layer_name)
|
Optional<FlyString> Parser::parse_layer_name(TokenStream<ComponentValue>& tokens, AllowBlankLayerName allow_blank_layer_name)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Cascade: @import with basic media query</title>
|
||||||
|
<link rel="author" title="Elika J. Etemad" href="http://fantasai.inkedblade.net/contact">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-cascade-3/#conditional-import">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-cascade-4/#conditional-import">
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css3-mediaqueries/#syntax">
|
||||||
|
<link rel="match" href="../../../../expected/wpt-import/css/css-cascade/reference/ref-filled-green-100px-square.xht">
|
||||||
|
<meta name="assert" content="Test passes on visual UAs if @import can be combined with a media query.">
|
||||||
|
<style>
|
||||||
|
@import "support/test-red.css";
|
||||||
|
@import "support/test-green.css"
|
||||||
|
(min-width: 1px) and /* assuming screen < 1km */ (max-width: 40000in), nonsense;
|
||||||
|
@import "support/test-red.css"
|
||||||
|
(max-width: 1px), nonsense;
|
||||||
|
div {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
padding: 5px; /* Avoids text antialiasing issues */
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
|
||||||
|
|
||||||
|
<div class="test">FAIL</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue