StyleElementUtils.cpp 3.4 KB

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