/src/serenity/Userland/Libraries/LibWeb/DOM/StyleElementUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2023, Preston Taylor <PrestonLeeTaylor@proton.me> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibWeb/CSS/Parser/Parser.h> |
8 | | #include <LibWeb/CSS/StyleComputer.h> |
9 | | #include <LibWeb/DOM/Document.h> |
10 | | #include <LibWeb/DOM/ShadowRoot.h> |
11 | | #include <LibWeb/DOM/StyleElementUtils.h> |
12 | | #include <LibWeb/Infra/Strings.h> |
13 | | |
14 | | namespace Web::DOM { |
15 | | |
16 | | // The user agent must run the "update a style block" algorithm whenever one of the following conditions occur: |
17 | | // FIXME: The element is popped off the stack of open elements of an HTML parser or XML parser. |
18 | | // |
19 | | // NOTE: This is basically done by children_changed() today: |
20 | | // The element's children changed steps run. |
21 | | // |
22 | | // NOTE: This is basically done by inserted() and removed_from() today: |
23 | | // The element is not on the stack of open elements of an HTML parser or XML parser, and it becomes connected or disconnected. |
24 | | // |
25 | | // https://html.spec.whatwg.org/multipage/semantics.html#update-a-style-block |
26 | | void StyleElementUtils::update_a_style_block(DOM::Element& style_element) |
27 | 0 | { |
28 | | // OPTIMIZATION: Skip parsing CSS if we're in the middle of parsing a HTML fragment. |
29 | | // The style block will be parsed upon insertion into a proper document. |
30 | 0 | if (style_element.document().is_temporary_document_for_fragment_parsing()) |
31 | 0 | return; |
32 | | |
33 | | // 1. Let element be the style element. |
34 | | // 2. If element has an associated CSS style sheet, remove the CSS style sheet in question. |
35 | | |
36 | 0 | if (m_associated_css_style_sheet) { |
37 | 0 | m_style_sheet_list->remove_a_css_style_sheet(*m_associated_css_style_sheet); |
38 | 0 | m_style_sheet_list = nullptr; |
39 | | |
40 | | // FIXME: This should probably be handled by StyleSheet::set_owner_node(). |
41 | 0 | m_associated_css_style_sheet = nullptr; |
42 | 0 | } |
43 | | |
44 | | // 3. If element is not connected, then return. |
45 | 0 | if (!style_element.is_connected()) |
46 | 0 | return; |
47 | | |
48 | | // 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. |
49 | 0 | auto type_attribute = style_element.attribute(HTML::AttributeNames::type); |
50 | 0 | if (type_attribute.has_value() && !type_attribute->is_empty() && !Infra::is_ascii_case_insensitive_match(type_attribute->bytes_as_string_view(), "text/css"sv)) |
51 | 0 | return; |
52 | | |
53 | | // FIXME: 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] |
54 | | |
55 | | // FIXME: This is a bit awkward, as the spec doesn't actually tell us when to parse the CSS text, |
56 | | // so we just do it here and pass the parsed sheet to create_a_css_style_sheet(). |
57 | 0 | auto* sheet = parse_css_stylesheet(CSS::Parser::ParsingContext(style_element.document()), style_element.text_content().value_or(String {})); |
58 | 0 | if (!sheet) |
59 | 0 | return; |
60 | | |
61 | | // FIXME: This should probably be handled by StyleSheet::set_owner_node(). |
62 | 0 | m_associated_css_style_sheet = sheet; |
63 | | |
64 | | // 6. Create a CSS style sheet with the following properties... |
65 | 0 | m_style_sheet_list = style_element.document_or_shadow_root_style_sheets(); |
66 | 0 | m_style_sheet_list->create_a_css_style_sheet( |
67 | 0 | "text/css"_string, |
68 | 0 | &style_element, |
69 | 0 | style_element.attribute(HTML::AttributeNames::media).value_or({}), |
70 | 0 | style_element.in_a_document_tree() |
71 | 0 | ? style_element.attribute(HTML::AttributeNames::title).value_or({}) |
72 | 0 | : String {}, |
73 | 0 | false, |
74 | 0 | true, |
75 | 0 | {}, |
76 | 0 | nullptr, |
77 | 0 | nullptr, |
78 | 0 | *sheet); |
79 | 0 | } |
80 | | |
81 | | void StyleElementUtils::visit_edges(JS::Cell::Visitor& visitor) |
82 | 0 | { |
83 | 0 | visitor.visit(m_associated_css_style_sheet); |
84 | 0 | visitor.visit(m_style_sheet_list); |
85 | 0 | } |
86 | | |
87 | | } |