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::bindings::codegen::Bindings::HTMLOrSVGElementBinding::FocusOptions;
15use crate::dom::bindings::codegen::Bindings::SVGElementBinding::SVGElementMethods;
16use crate::dom::bindings::inheritance::Castable;
17use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
18use crate::dom::css::cssstyledeclaration::{
19 CSSModificationAccess, CSSStyleDeclaration, CSSStyleOwner,
20};
21use crate::dom::document::Document;
22use crate::dom::document::focus::FocusableArea;
23use crate::dom::element::attributes::storage::AttrRef;
24use crate::dom::element::{AttributeMutation, Element};
25use crate::dom::node::{Node, NodeTraits};
26use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement};
27use crate::dom::virtualmethods::VirtualMethods;
28
29#[dom_struct]
30pub(crate) struct SVGElement {
31 element: Element,
32 style_decl: MutNullableDom<CSSStyleDeclaration>,
33}
34
35impl SVGElement {
36 fn new_inherited(
37 tag_name: LocalName,
38 prefix: Option<Prefix>,
39 document: &Document,
40 ) -> SVGElement {
41 SVGElement::new_inherited_with_state(ElementState::empty(), tag_name, prefix, document)
42 }
43
44 pub(crate) fn new_inherited_with_state(
45 state: ElementState,
46 tag_name: LocalName,
47 prefix: Option<Prefix>,
48 document: &Document,
49 ) -> SVGElement {
50 SVGElement {
51 element: Element::new_inherited_with_state(state, tag_name, ns!(svg), prefix, document),
52 style_decl: Default::default(),
53 }
54 }
55
56 pub(crate) fn new(
57 cx: &mut js::context::JSContext,
58 tag_name: LocalName,
59 prefix: Option<Prefix>,
60 document: &Document,
61 proto: Option<HandleObject>,
62 ) -> DomRoot<SVGElement> {
63 Node::reflect_node_with_proto(
64 cx,
65 Box::new(SVGElement::new_inherited(tag_name, prefix, document)),
66 document,
67 proto,
68 )
69 }
70
71 fn as_element(&self) -> &Element {
72 self.upcast::<Element>()
73 }
74}
75
76impl VirtualMethods for SVGElement {
77 fn super_type(&self) -> Option<&dyn VirtualMethods> {
78 Some(self.as_element() as &dyn VirtualMethods)
79 }
80
81 fn attribute_mutated(
82 &self,
83 cx: &mut js::context::JSContext,
84 attr: AttrRef<'_>,
85 mutation: AttributeMutation,
86 ) {
87 self.super_type()
88 .unwrap()
89 .attribute_mutated(cx, attr, mutation);
90 let element = self.as_element();
91 if let (&local_name!("nonce"), mutation) = (attr.local_name(), mutation) {
92 match mutation {
93 AttributeMutation::Set(..) => {
94 let nonce = &**attr.value();
95 element.update_nonce_internal_slot(nonce.to_owned());
96 },
97 AttributeMutation::Removed => {
98 element.update_nonce_internal_slot(String::new());
99 },
100 }
101 }
102 }
103}
104
105impl SVGElementMethods<crate::DomTypeHolder> for SVGElement {
106 fn Style(&self, cx: &mut JSContext) -> DomRoot<CSSStyleDeclaration> {
108 self.style_decl.or_init(|| {
109 let global = self.owner_window();
110 CSSStyleDeclaration::new(
111 cx,
112 &global,
113 CSSStyleOwner::Element(Dom::from_ref(self.upcast())),
114 None,
115 CSSModificationAccess::ReadWrite,
116 )
117 })
118 }
119
120 global_event_handlers!();
122
123 fn Nonce(&self) -> DOMString {
125 self.as_element().nonce_value().into()
126 }
127
128 fn SetNonce(&self, _cx: &mut JSContext, value: DOMString) {
130 self.as_element()
131 .update_nonce_internal_slot(String::from(value))
132 }
133
134 fn Autofocus(&self) -> bool {
136 self.element.has_attribute(&local_name!("autofocus"))
137 }
138
139 fn SetAutofocus(&self, cx: &mut JSContext, autofocus: bool) {
141 self.element
142 .set_bool_attribute(cx, &local_name!("autofocus"), autofocus);
143 }
144
145 fn Focus(&self, cx: &mut js::context::JSContext, options: &FocusOptions) {
147 if !self.upcast::<Node>().run_the_focusing_steps(cx, None) {
152 return;
156 }
157
158 if !options.preventScroll {
166 let scroll_axis = ScrollAxisState {
167 position: ScrollLogicalPosition::Center,
168 requirement: ScrollRequirement::IfNotVisible,
169 };
170 self.upcast::<Element>().scroll_into_view_with_options(
171 cx,
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_attribute(cx, &local_name!("tabindex"), tab_index.into());
203 }
204}