1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::rust::HandleObject;
8use script_bindings::str::DOMString;
9use stylo_dom::ElementState;
10
11use crate::dom::attr::Attr;
12use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
13use crate::dom::bindings::codegen::Bindings::SVGElementBinding::SVGElementMethods;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
16use crate::dom::cssstyledeclaration::{CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner};
17use crate::dom::document::{Document, FocusInitiator};
18use crate::dom::element::{AttributeMutation, Element};
19use crate::dom::node::{Node, NodeTraits};
20use crate::dom::virtualmethods::VirtualMethods;
21use crate::script_runtime::CanGc;
22
23#[dom_struct]
24pub(crate) struct SVGElement {
25 element: Element,
26 style_decl: MutNullableDom<CSSStyleDeclaration>,
27}
28
29impl SVGElement {
30 fn new_inherited(
31 tag_name: LocalName,
32 prefix: Option<Prefix>,
33 document: &Document,
34 ) -> SVGElement {
35 SVGElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document)
36 }
37
38 pub(crate) fn new_inherited_with_state(
39 state: ElementState,
40 tag_name: LocalName,
41 prefix: Option<Prefix>,
42 document: &Document,
43 ) -> SVGElement {
44 SVGElement {
45 element: Element::new_inherited_with_state(state, tag_name, ns!(svg), prefix, document),
46 style_decl: Default::default(),
47 }
48 }
49
50 pub(crate) fn new(
51 tag_name: LocalName,
52 prefix: Option<Prefix>,
53 document: &Document,
54 proto: Option<HandleObject>,
55 can_gc: CanGc,
56 ) -> DomRoot<SVGElement> {
57 Node::reflect_node_with_proto(
58 Box::new(SVGElement::new_inherited(tag_name, prefix, document)),
59 document,
60 proto,
61 can_gc,
62 )
63 }
64
65 fn as_element(&self) -> &Element {
66 self.upcast::<Element>()
67 }
68}
69
70impl VirtualMethods for SVGElement {
71 fn super_type(&self) -> Option<&dyn VirtualMethods> {
72 Some(self.as_element() as &dyn VirtualMethods)
73 }
74
75 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
76 self.super_type()
77 .unwrap()
78 .attribute_mutated(attr, mutation, can_gc);
79 let element = self.as_element();
80 if let (&local_name!("nonce"), mutation) = (attr.local_name(), mutation) {
81 match mutation {
82 AttributeMutation::Set(_) => {
83 let nonce = &**attr.value();
84 element.update_nonce_internal_slot(nonce.to_owned());
85 },
86 AttributeMutation::Removed => {
87 element.update_nonce_internal_slot(String::new());
88 },
89 }
90 }
91 }
92}
93
94impl SVGElementMethods<crate::DomTypeHolder> for SVGElement {
95 fn Style(&self) -> DomRoot<CSSStyleDeclaration> {
97 self.style_decl.or_init(|| {
98 let global = self.owner_window();
99 CSSStyleDeclaration::new(
100 &global,
101 CSSStyleOwner::Element(Dom::from_ref(self.upcast())),
102 None,
103 CSSModificationAccess::ReadWrite,
104 CanGc::note(),
105 )
106 })
107 }
108
109 global_event_handlers!();
111
112 fn Nonce(&self) -> DOMString {
114 self.as_element().nonce_value().into()
115 }
116
117 fn SetNonce(&self, value: DOMString) {
119 self.as_element()
120 .update_nonce_internal_slot(value.to_string())
121 }
122
123 fn Autofocus(&self) -> bool {
125 self.element.has_attribute(&local_name!("autofocus"))
126 }
127
128 fn SetAutofocus(&self, autofocus: bool, can_gc: CanGc) {
130 self.element
131 .set_bool_attribute(&local_name!("autofocus"), autofocus, can_gc);
132 }
133
134 fn Focus(&self, options: &FocusOptions) {
136 let document = self.element.owner_document();
137 document.request_focus_with_options(
138 Some(&self.element),
139 FocusInitiator::Local,
140 FocusOptions {
141 preventScroll: options.preventScroll,
142 },
143 CanGc::note(),
144 );
145 }
146}