script/dom/svg/
svgelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::context::JSContext;
8use js::rust::HandleObject;
9use script_bindings::codegen::GenericBindings::ElementBinding::ScrollLogicalPosition;
10use script_bindings::codegen::GenericBindings::WindowBinding::ScrollBehavior;
11use script_bindings::str::DOMString;
12use stylo_dom::ElementState;
13
14use crate::dom::attr::Attr;
15use crate::dom::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
16use crate::dom::bindings::codegen::Bindings::SVGElementBinding::SVGElementMethods;
17use crate::dom::bindings::inheritance::Castable;
18use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
19use crate::dom::css::cssstyledeclaration::{
20 CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner,
21};
22use crate::dom::document::Document;
23use crate::dom::document::focus::FocusableArea;
24use crate::dom::element::{AttributeMutation, Element};
25use crate::dom::node::{Node, NodeTraits};
26use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement};
27use crate::dom::virtualmethods::VirtualMethods;
28use crate::script_runtime::CanGc;
29
30#[dom_struct]
31pub(crate) struct SVGElement {
32 element: Element,
33 style_decl: MutNullableDom<CSSStyleDeclaration>,
34}
35
36impl SVGElement {
37 fn new_inherited(
38 tag_name: LocalName,
39 prefix: Option<Prefix>,
40 document: &Document,
41 ) -> SVGElement {
42 SVGElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document)
43 }
44
45 pub(crate) fn new_inherited_with_state(
46 state: ElementState,
47 tag_name: LocalName,
48 prefix: Option<Prefix>,
49 document: &Document,
50 ) -> SVGElement {
51 SVGElement {
52 element: Element::new_inherited_with_state(state, tag_name, ns!(svg), prefix, document),
53 style_decl: Default::default(),
54 }
55 }
56
57 pub(crate) fn new(
58 cx: &mut js::context::JSContext,
59 tag_name: LocalName,
60 prefix: Option<Prefix>,
61 document: &Document,
62 proto: Option<HandleObject>,
63 ) -> DomRoot<SVGElement> {
64 Node::reflect_node_with_proto(
65 cx,
66 Box::new(SVGElement::new_inherited(tag_name, prefix, document)),
67 document,
68 proto,
69 )
70 }
71
72 fn as_element(&self) -> &Element {
73 self.upcast::<Element>()
74 }
75}
76
77impl VirtualMethods for SVGElement {
78 fn super_type(&self) -> Option<&dyn VirtualMethods> {
79 Some(self.as_element() as &dyn VirtualMethods)
80 }
81
82 fn attribute_mutated(
83 &self,
84 cx: &mut js::context::JSContext,
85 attr: &Attr,
86 mutation: AttributeMutation,
87 ) {
88 self.super_type()
89 .unwrap()
90 .attribute_mutated(cx, attr, mutation);
91 let element = self.as_element();
92 if let (&local_name!("nonce"), mutation) = (attr.local_name(), mutation) {
93 match mutation {
94 AttributeMutation::Set(..) => {
95 let nonce = &**attr.value();
96 element.update_nonce_internal_slot(nonce.to_owned());
97 },
98 AttributeMutation::Removed => {
99 element.update_nonce_internal_slot(String::new());
100 },
101 }
102 }
103 }
104}
105
106impl SVGElementMethods<crate::DomTypeHolder> for SVGElement {
107 fn Style(&self) -> DomRoot<CSSStyleDeclaration> {
109 self.style_decl.or_init(|| {
110 let global = self.owner_window();
111 CSSStyleDeclaration::new(
112 &global,
113 CSSStyleOwner::Element(Dom::from_ref(self.upcast())),
114 None,
115 CSSModificationAccess::ReadWrite,
116 CanGc::deprecated_note(),
117 )
118 })
119 }
120
121 global_event_handlers!();
123
124 fn Nonce(&self) -> DOMString {
126 self.as_element().nonce_value().into()
127 }
128
129 fn SetNonce(&self, _cx: &mut JSContext, value: DOMString) {
131 self.as_element()
132 .update_nonce_internal_slot(value.to_string())
133 }
134
135 fn Autofocus(&self) -> bool {
137 self.element.has_attribute(&local_name!("autofocus"))
138 }
139
140 fn SetAutofocus(&self, cx: &mut JSContext, autofocus: bool) {
142 self.element
143 .set_bool_attribute(&local_name!("autofocus"), autofocus, CanGc::from_cx(cx));
144 }
145
146 fn Focus(&self, cx: &mut js::context::JSContext, options: &FocusOptions) {
148 if !self.upcast::<Node>().run_the_focusing_steps(cx, None) {
153 return;
157 }
158
159 if !options.preventScroll {
167 let scroll_axis = ScrollAxisState {
168 position: ScrollLogicalPosition::Center,
169 requirement: ScrollRequirement::IfNotVisible,
170 };
171 self.upcast::<Element>().scroll_into_view_with_options(
172 ScrollBehavior::Smooth,
173 scroll_axis,
174 scroll_axis,
175 None,
176 None,
177 );
178 }
179 }
180
181 fn Blur(&self, cx: &mut js::context::JSContext) {
183 if !self.as_element().focus_state() {
186 return;
187 }
188 self.owner_document()
190 .focus_handler()
191 .focus(cx, FocusableArea::Viewport);
192 }
193
194 fn TabIndex(&self) -> i32 {
196 self.element.tab_index()
197 }
198
199 fn SetTabIndex(&self, cx: &mut JSContext, tab_index: i32) {
201 self.element
202 .set_int_attribute(&local_name!("tabindex"), tab_index, CanGc::from_cx(cx));
203 }
204}