SVGElement.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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/Bindings/SVGElementPrototype.h>
  10. #include <LibWeb/CSS/StyleProperties.h>
  11. #include <LibWeb/DOM/Document.h>
  12. #include <LibWeb/DOM/ShadowRoot.h>
  13. #include <LibWeb/HTML/DOMStringMap.h>
  14. #include <LibWeb/SVG/SVGElement.h>
  15. #include <LibWeb/SVG/SVGUseElement.h>
  16. namespace Web::SVG {
  17. SVGElement::SVGElement(DOM::Document& document, DOM::QualifiedName qualified_name)
  18. : Element(document, move(qualified_name))
  19. {
  20. }
  21. void SVGElement::initialize(JS::Realm& realm)
  22. {
  23. Base::initialize(realm);
  24. WEB_SET_PROTOTYPE_FOR_INTERFACE(SVGElement);
  25. }
  26. void SVGElement::visit_edges(Cell::Visitor& visitor)
  27. {
  28. Base::visit_edges(visitor);
  29. visitor.visit(m_dataset);
  30. }
  31. JS::NonnullGCPtr<HTML::DOMStringMap> SVGElement::dataset()
  32. {
  33. if (!m_dataset)
  34. m_dataset = HTML::DOMStringMap::create(*this);
  35. return *m_dataset;
  36. }
  37. void SVGElement::attribute_changed(FlyString const& name, Optional<String> const& value)
  38. {
  39. Base::attribute_changed(name, value);
  40. update_use_elements_that_reference_this();
  41. }
  42. void SVGElement::inserted()
  43. {
  44. Base::inserted();
  45. update_use_elements_that_reference_this();
  46. }
  47. void SVGElement::children_changed()
  48. {
  49. Base::children_changed();
  50. update_use_elements_that_reference_this();
  51. }
  52. void SVGElement::update_use_elements_that_reference_this()
  53. {
  54. if (is<SVGUseElement>(this)
  55. // If this element is in a shadow root, it already represents a clone and is not itself referenced.
  56. || is<DOM::ShadowRoot>(this->root())
  57. // If this does not have an id it cannot be referenced, no point in searching the entire DOM tree.
  58. || !id().has_value()
  59. // An unconnected node cannot have valid references.
  60. // This also prevents searches for elements that are in the process of being constructed - as clones.
  61. || !this->is_connected()
  62. // Each use element already listens for the completely_loaded event and then clones its referece,
  63. // we do not have to also clone it in the process of initial DOM building.
  64. || !document().is_completely_loaded()) {
  65. return;
  66. }
  67. document().for_each_in_subtree_of_type<SVGUseElement>([this](SVGUseElement& use_element) {
  68. use_element.svg_element_changed(*this);
  69. return TraversalDecision::Continue;
  70. });
  71. }
  72. void SVGElement::removed_from(Node* parent)
  73. {
  74. Base::removed_from(parent);
  75. remove_from_use_element_that_reference_this();
  76. }
  77. void SVGElement::remove_from_use_element_that_reference_this()
  78. {
  79. if (is<SVGUseElement>(this) || !id().has_value()) {
  80. return;
  81. }
  82. document().for_each_in_subtree_of_type<SVGUseElement>([this](SVGUseElement& use_element) {
  83. use_element.svg_element_removed(*this);
  84. return TraversalDecision::Continue;
  85. });
  86. }
  87. void SVGElement::focus()
  88. {
  89. dbgln("(STUBBED) SVGElement::focus()");
  90. }
  91. void SVGElement::blur()
  92. {
  93. dbgln("(STUBBED) SVGElement::blur()");
  94. }
  95. JS::NonnullGCPtr<SVGAnimatedLength> SVGElement::svg_animated_length_for_property(CSS::PropertyID property) const
  96. {
  97. // FIXME: Create a proper animated value when animations are supported.
  98. auto make_length = [&] {
  99. if (auto const* style = computed_css_values(); style) {
  100. if (auto length = style->length_percentage(property); length.has_value())
  101. return SVGLength::from_length_percentage(realm(), *length);
  102. }
  103. return SVGLength::create(realm(), 0, 0.0f);
  104. };
  105. return SVGAnimatedLength::create(realm(), make_length(), make_length());
  106. }
  107. }