SVGElement.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  3. * Copyright (c) 2023, Preston Taylor <95388976+PrestonLTaylor@users.noreply.github.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibWeb/Bindings/ExceptionOrUtils.h>
  8. #include <LibWeb/Bindings/Intrinsics.h>
  9. #include <LibWeb/DOM/Document.h>
  10. #include <LibWeb/DOM/ShadowRoot.h>
  11. #include <LibWeb/HTML/DOMStringMap.h>
  12. #include <LibWeb/SVG/SVGElement.h>
  13. #include <LibWeb/SVG/SVGUseElement.h>
  14. namespace Web::SVG {
  15. SVGElement::SVGElement(DOM::Document& document, DOM::QualifiedName qualified_name)
  16. : Element(document, move(qualified_name))
  17. {
  18. }
  19. JS::ThrowCompletionOr<void> SVGElement::initialize(JS::Realm& realm)
  20. {
  21. MUST_OR_THROW_OOM(Base::initialize(realm));
  22. set_prototype(&Bindings::ensure_web_prototype<Bindings::SVGElementPrototype>(realm, "SVGElement"));
  23. m_dataset = TRY(Bindings::throw_dom_exception_if_needed(realm.vm(), [&]() {
  24. return HTML::DOMStringMap::create(*this);
  25. }));
  26. return {};
  27. }
  28. void SVGElement::visit_edges(Cell::Visitor& visitor)
  29. {
  30. Base::visit_edges(visitor);
  31. visitor.visit(m_dataset);
  32. }
  33. void SVGElement::attribute_changed(DeprecatedFlyString const& name, DeprecatedString const& value)
  34. {
  35. Base::attribute_changed(name, value);
  36. update_use_elements_that_reference_this();
  37. }
  38. void SVGElement::inserted()
  39. {
  40. Base::inserted();
  41. update_use_elements_that_reference_this();
  42. }
  43. void SVGElement::children_changed()
  44. {
  45. Base::children_changed();
  46. update_use_elements_that_reference_this();
  47. }
  48. void SVGElement::update_use_elements_that_reference_this()
  49. {
  50. if (is<SVGUseElement>(this)
  51. // If this element is in a shadow root, it already represents a clone and is not itself referenced.
  52. || is<DOM::ShadowRoot>(this->root())
  53. // If this does not have an id it cannot be referenced, no point in searching the entire DOM tree.
  54. || !this->has_attribute(HTML::AttributeNames::id)
  55. // An unconnected node cannot have valid references.
  56. // This also prevents searches for elements that are in the process of being constructed - as clones.
  57. || !this->is_connected()
  58. // Each use element already listens for the completely_loaded event and then clones its referece,
  59. // we do not have to also clone it in the process of initial DOM building.
  60. || !document().is_completely_loaded()) {
  61. return;
  62. }
  63. document().for_each_in_subtree_of_type<SVGUseElement>([this](SVGUseElement& use_element) {
  64. use_element.svg_element_changed(*this);
  65. return IterationDecision::Continue;
  66. });
  67. }
  68. void SVGElement::removed_from(Node* parent)
  69. {
  70. Base::removed_from(parent);
  71. remove_from_use_element_that_reference_this();
  72. }
  73. void SVGElement::remove_from_use_element_that_reference_this()
  74. {
  75. if (is<SVGUseElement>(this) || !this->has_attribute(HTML::AttributeNames::id)) {
  76. return;
  77. }
  78. document().for_each_in_subtree_of_type<SVGUseElement>([this](SVGUseElement& use_element) {
  79. use_element.svg_element_removed(*this);
  80. return IterationDecision::Continue;
  81. });
  82. }
  83. }