2023-06-08 16:07:12 +01:00
/*
* Copyright ( c ) 2023 , Preston Taylor < PrestonLeeTaylor @ proton . me >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include <LibWeb/CSS/Parser/Parser.h>
2024-03-08 19:27:24 +01:00
# include <LibWeb/CSS/StyleComputer.h>
2024-12-03 16:57:18 +00:00
# include <LibWeb/ContentSecurityPolicy/BlockingAlgorithms.h>
2023-06-08 16:07:12 +01:00
# include <LibWeb/DOM/Document.h>
2024-07-23 09:53:32 +02:00
# include <LibWeb/DOM/ShadowRoot.h>
2023-06-08 16:07:12 +01:00
# include <LibWeb/DOM/StyleElementUtils.h>
# include <LibWeb/Infra/Strings.h>
namespace Web : : DOM {
// The user agent must run the "update a style block" algorithm whenever one of the following conditions occur:
// FIXME: The element is popped off the stack of open elements of an HTML parser or XML parser.
//
// NOTE: This is basically done by children_changed() today:
// The element's children changed steps run.
//
// NOTE: This is basically done by inserted() and removed_from() today:
// The element is not on the stack of open elements of an HTML parser or XML parser, and it becomes connected or disconnected.
//
// https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block
2024-09-21 08:11:49 +02:00
void StyleElementUtils : : update_a_style_block ( DOM : : Element & style_element )
2023-06-08 16:07:12 +01:00
{
2023-08-09 15:10:00 +02:00
// OPTIMIZATION: Skip parsing CSS if we're in the middle of parsing a HTML fragment.
// The style block will be parsed upon insertion into a proper document.
if ( style_element . document ( ) . is_temporary_document_for_fragment_parsing ( ) )
return ;
2023-06-08 16:07:12 +01:00
// 1. Let element be the style element.
// 2. If element has an associated CSS style sheet, remove the CSS style sheet in question.
if ( m_associated_css_style_sheet ) {
2024-09-21 08:11:49 +02:00
m_style_sheet_list - > remove_a_css_style_sheet ( * m_associated_css_style_sheet ) ;
m_style_sheet_list = nullptr ;
2023-06-08 16:07:12 +01:00
// FIXME: This should probably be handled by StyleSheet::set_owner_node().
m_associated_css_style_sheet = nullptr ;
}
// 3. If element is not connected, then return.
if ( ! style_element . is_connected ( ) )
return ;
// 4. If element's type attribute is present and its value is neither the empty string nor an ASCII case-insensitive match for "text/css", then return.
2023-10-10 15:00:58 +03:30
auto type_attribute = style_element . attribute ( HTML : : AttributeNames : : type ) ;
2025-05-18 15:04:56 +12:00
if ( type_attribute . has_value ( ) & & ! type_attribute - > is_empty ( ) & & ! type_attribute - > bytes_as_string_view ( ) . equals_ignoring_ascii_case ( " text/css " sv ) )
2023-06-08 16:07:12 +01:00
return ;
2024-12-03 16:57:18 +00:00
// 5. If the Should element's inline behavior be blocked by Content Security Policy? algorithm returns "Blocked" when executed upon the style element, "style", and the style element's child text content, then return. [CSP]
if ( ContentSecurityPolicy : : should_elements_inline_type_behavior_be_blocked_by_content_security_policy ( style_element . realm ( ) , style_element , ContentSecurityPolicy : : Directives : : Directive : : InlineType : : Style , style_element . child_text_content ( ) ) = = ContentSecurityPolicy : : Directives : : Directive : : Result : : Blocked )
return ;
2023-06-08 16:07:12 +01:00
2025-04-14 13:53:11 +01:00
// 6. Create a CSS style sheet with the following properties:
// type
// text/css
// owner node
// element
// media
// The media attribute of element.
// title
// The title attribute of element, if element is in a document tree, or the empty string otherwise.
// alternate flag
// Unset.
// origin-clean flag
// Set.
// location
// parent CSS style sheet
// owner CSS rule
// null
// disabled flag
// Left at its default value.
// CSS rules
// Left uninitialized.
2024-09-21 08:11:49 +02:00
m_style_sheet_list = style_element . document_or_shadow_root_style_sheets ( ) ;
2025-04-14 13:53:11 +01:00
m_associated_css_style_sheet = m_style_sheet_list - > create_a_css_style_sheet (
style_element . text_content ( ) . value_or ( String { } ) ,
2023-12-01 17:02:50 +00:00
" text/css " _string ,
2023-06-08 16:07:12 +01:00
& style_element ,
2023-12-01 17:02:50 +00:00
style_element . attribute ( HTML : : AttributeNames : : media ) . value_or ( { } ) ,
style_element . in_a_document_tree ( )
? style_element . attribute ( HTML : : AttributeNames : : title ) . value_or ( { } )
: String { } ,
2025-04-14 13:53:11 +01:00
CSS : : StyleSheetList : : Alternate : : No ,
CSS : : StyleSheetList : : OriginClean : : Yes ,
2025-05-02 11:48:40 +01:00
// AD-HOC: Use the document's base URL as the location instead. Spec issue: https://github.com/whatwg/html/issues/11281
style_element . document ( ) . base_url ( ) ,
2023-06-08 16:07:12 +01:00
nullptr ,
2025-04-14 13:53:11 +01:00
nullptr ) ;
2025-04-20 11:31:57 +02:00
// 7. If element contributes a script-blocking style sheet, append element to its node document's script-blocking style sheet set.
if ( style_element . contributes_a_script_blocking_style_sheet ( ) )
style_element . document ( ) . script_blocking_style_sheet_set ( ) . set ( style_element ) ;
// FIXME: 8. If element's media attribute's value matches the environment and element is potentially render-blocking, then block rendering on element.
2023-06-08 16:07:12 +01:00
}
2024-09-21 08:11:49 +02:00
void StyleElementUtils : : visit_edges ( JS : : Cell : : Visitor & visitor )
{
visitor . visit ( m_associated_css_style_sheet ) ;
visitor . visit ( m_style_sheet_list ) ;
}
2023-06-08 16:07:12 +01:00
}