2021-02-21 18:36:34 +02:00
/*
* Copyright ( c ) 2021 , the SerenityOS developers .
2024-12-20 20:25:40 +00:00
* Copyright ( c ) 2021 - 2024 , Sam Atkins < sam @ ladybird . org >
2024-10-12 16:52:36 +02:00
* Copyright ( c ) 2022 - 2024 , Andreas Kling < andreas @ ladybird . org >
2021-02-21 18:36:34 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2021-02-21 18:36:34 +02:00
*/
2021-11-18 17:34:53 +00:00
# include <AK/Debug.h>
2024-12-20 20:25:40 +00:00
# include <AK/ScopeGuard.h>
2024-10-12 16:52:36 +02:00
# include <LibTextCodec/Decoder.h>
2024-03-18 16:22:27 +13:00
# include <LibURL/URL.h>
2022-09-24 16:34:04 -06:00
# include <LibWeb/Bindings/CSSImportRulePrototype.h>
# include <LibWeb/Bindings/Intrinsics.h>
2021-02-21 18:36:34 +02:00
# include <LibWeb/CSS/CSSImportRule.h>
2024-12-20 20:25:40 +00:00
# include <LibWeb/CSS/Fetch.h>
2021-11-18 17:34:53 +00:00
# include <LibWeb/CSS/Parser/Parser.h>
2023-05-08 06:37:18 +02:00
# include <LibWeb/CSS/StyleComputer.h>
2021-11-18 17:34:53 +00:00
# include <LibWeb/DOM/Document.h>
2022-08-28 13:42:07 +02:00
# include <LibWeb/HTML/Window.h>
2021-02-21 18:36:34 +02:00
namespace Web : : CSS {
2024-11-15 04:01:23 +13:00
GC_DEFINE_ALLOCATOR ( CSSImportRule ) ;
2023-11-19 19:47:52 +01:00
2024-11-15 04:01:23 +13:00
GC : : Ref < CSSImportRule > CSSImportRule : : create ( URL : : URL url , DOM : : Document & document )
2022-08-07 15:46:44 +02:00
{
2022-09-24 16:34:04 -06:00
auto & realm = document . realm ( ) ;
2024-11-14 05:50:17 +13:00
return realm . create < CSSImportRule > ( move ( url ) , document ) ;
2022-08-07 15:46:44 +02:00
}
2024-03-18 16:22:27 +13:00
CSSImportRule : : CSSImportRule ( URL : : URL url , DOM : : Document & document )
2024-10-28 20:16:28 +01:00
: CSSRule ( document . realm ( ) , Type : : Import )
2022-08-07 15:46:44 +02:00
, m_url ( move ( url ) )
2021-11-18 17:34:53 +00:00
, m_document ( document )
2021-02-21 18:36:34 +02:00
{
}
2023-08-07 08:41:28 +02:00
void CSSImportRule : : initialize ( JS : : Realm & realm )
2023-01-10 06:28:20 -05:00
{
2023-08-07 08:41:28 +02:00
Base : : initialize ( realm ) ;
2024-03-16 13:13:08 +01:00
WEB_SET_PROTOTYPE_FOR_INTERFACE ( CSSImportRule ) ;
2023-01-10 06:28:20 -05:00
}
2022-08-07 15:46:44 +02:00
void CSSImportRule : : visit_edges ( Cell : : Visitor & visitor )
{
Base : : visit_edges ( visitor ) ;
2022-09-03 15:44:06 +02:00
visitor . visit ( m_document ) ;
2022-08-07 15:46:44 +02:00
visitor . visit ( m_style_sheet ) ;
}
2024-12-20 20:25:40 +00:00
void CSSImportRule : : set_parent_style_sheet ( CSSStyleSheet * parent_style_sheet )
{
Base : : set_parent_style_sheet ( parent_style_sheet ) ;
// Crude detection of whether we're already fetching.
if ( m_style_sheet | | m_document_load_event_delayer . has_value ( ) )
return ;
fetch ( ) ;
}
2021-10-15 19:38:39 +01:00
// https://www.w3.org/TR/cssom/#serialize-a-css-rule
2023-11-20 23:16:39 +13:00
String CSSImportRule : : serialized ( ) const
2021-10-01 19:57:45 +02:00
{
StringBuilder builder ;
// The result of concatenating the following:
// 1. The string "@import" followed by a single SPACE (U+0020).
builder . append ( " @import " sv ) ;
// 2. The result of performing serialize a URL on the rule’ s location.
2024-12-03 22:31:33 +13:00
serialize_a_url ( builder , m_url . to_string ( ) ) ;
2021-10-01 19:57:45 +02:00
// 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.
// 4. The string ";", i.e., SEMICOLON (U+003B).
builder . append ( ' ; ' ) ;
2023-11-20 23:16:39 +13:00
return MUST ( builder . to_string ( ) ) ;
2021-10-01 19:57:45 +02:00
}
2024-12-20 20:25:40 +00:00
// https://drafts.csswg.org/css-cascade-4/#fetch-an-import
void CSSImportRule : : fetch ( )
2021-11-18 17:34:53 +00:00
{
2024-12-20 20:25:40 +00:00
dbgln_if ( CSS_LOADER_DEBUG , " CSSImportRule: Loading import URL: {} " , m_url ) ;
// To fetch an @import, given an @import rule rule:
// 1. Let parentStylesheet be rule’ s parent CSS style sheet. [CSSOM]
VERIFY ( parent_style_sheet ( ) ) ;
auto & parent_style_sheet = * this - > parent_style_sheet ( ) ;
// FIXME: 2. If rule has a <supports-condition>, and that condition is not true, return.
// 3. Let parsedUrl be the result of the URL parser steps with rule’ s URL and parentStylesheet’ s location.
// If the algorithm returns an error, return. [CSSOM]
// FIXME: Stop producing a URL::URL when parsing the @import
auto parsed_url = url ( ) . to_string ( ) ;
// FIXME: Figure out the "correct" way to delay the load event.
m_document_load_event_delayer . emplace ( * m_document ) ;
// 4. Fetch a style resource from parsedUrl, with stylesheet parentStylesheet, destination "style", CORS mode "no-cors", and processResponse being the following steps given response response and byte stream, null or failure byteStream:
fetch_a_style_resource ( parsed_url , parent_style_sheet , Fetch : : Infrastructure : : Request : : Destination : : Style , CorsMode : : NoCors ,
[ strong_this = GC : : Ref { * this } , parent_style_sheet = GC : : Ref { parent_style_sheet } ] ( auto response , auto maybe_byte_stream ) {
// AD-HOC: Stop delaying the load event.
ScopeGuard guard = [ strong_this ] {
strong_this - > m_document_load_event_delayer . clear ( ) ;
} ;
// 1. If byteStream is not a byte stream, return.
auto byte_stream = maybe_byte_stream . template get_pointer < ByteBuffer > ( ) ;
if ( ! byte_stream )
return ;
// FIXME: 2. If parentStylesheet is in quirks mode and response is CORS-same-origin, let content type be "text/css".
// Otherwise, let content type be the Content Type metadata of response.
auto content_type = " text/css " sv ;
// 3. If content type is not "text/css", return.
if ( content_type ! = " text/css " sv ) {
dbgln_if ( CSS_LOADER_DEBUG , " CSSImportRule: Rejecting loaded style sheet; content type isn't text/css; is: '{}' " , content_type ) ;
return ;
}
// 4. Let importedStylesheet be the result of parsing byteStream given parsedUrl.
// FIXME: Tidy up our parsing API. For now, do the decoding here.
// FIXME: Get the encoding from the response somehow.
auto encoding = " utf-8 " sv ;
auto maybe_decoder = TextCodec : : decoder_for ( encoding ) ;
if ( ! maybe_decoder . has_value ( ) ) {
dbgln_if ( CSS_LOADER_DEBUG , " CSSImportRule: Failed to decode CSS file: {} Unsupported encoding: {} " , strong_this - > url ( ) , encoding ) ;
return ;
}
auto & decoder = maybe_decoder . release_value ( ) ;
auto decoded_or_error = TextCodec : : convert_input_to_utf8_using_given_decoder_unless_there_is_a_byte_order_mark ( decoder , * byte_stream ) ;
if ( decoded_or_error . is_error ( ) ) {
dbgln_if ( CSS_LOADER_DEBUG , " CSSImportRule: Failed to decode CSS file: {} Encoding was: {} " , strong_this - > url ( ) , encoding ) ;
return ;
}
auto decoded = decoded_or_error . release_value ( ) ;
2025-02-05 12:08:27 +00:00
auto * imported_style_sheet = parse_css_stylesheet ( Parser : : ParsingParams ( * strong_this - > m_document , strong_this - > url ( ) ) , decoded , strong_this - > url ( ) ) ;
2024-12-20 20:25:40 +00:00
// 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 ( ) ) ;
// 6. If response is not CORS-same-origin, unset importedStylesheet’ s origin-clean flag.
if ( ! response - > is_cors_cross_origin ( ) )
imported_style_sheet - > set_origin_clean ( false ) ;
// 7. Set rule’ s styleSheet to importedStylesheet.
strong_this - > set_style_sheet ( * imported_style_sheet ) ;
} ) ;
2021-11-18 17:34:53 +00:00
}
2024-12-20 20:25:40 +00:00
void CSSImportRule : : set_style_sheet ( GC : : Ref < CSSStyleSheet > style_sheet )
2021-11-18 17:34:53 +00:00
{
2024-12-20 20:25:40 +00:00
m_style_sheet = style_sheet ;
2024-08-23 17:47:05 +01:00
m_style_sheet - > set_owner_css_rule ( this ) ;
2022-03-14 20:31:57 +01:00
m_document - > style_computer ( ) . invalidate_rule_cache ( ) ;
2023-08-12 17:28:40 +02:00
m_document - > style_computer ( ) . load_fonts_from_sheet ( * m_style_sheet ) ;
2024-09-04 10:01:08 +02:00
m_document - > invalidate_style ( DOM : : StyleInvalidationReason : : CSSImportRule ) ;
2021-11-18 17:34:53 +00:00
}
2021-02-21 18:36:34 +02:00
}