script/dom/svg/
svgelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name, ns};
7use js::rust::HandleObject;
8use script_bindings::codegen::GenericBindings::ElementBinding::ScrollLogicalPosition;
9use script_bindings::codegen::GenericBindings::WindowBinding::ScrollBehavior;
10use script_bindings::str::DOMString;
11use stylo_dom::ElementState;
12
13use crate::dom::attr::Attr;
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::{FocusInitiator, FocusOperation, FocusableArea};
23use crate::dom::element::{AttributeMutation, Element};
24use crate::dom::node::{Node, NodeTraits};
25use crate::dom::scrolling_box::{ScrollAxisState, ScrollRequirement};
26use crate::dom::virtualmethods::VirtualMethods;
27use crate::script_runtime::CanGc;
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: &Attr,
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) -> DomRoot<CSSStyleDeclaration> {
108 self.style_decl.or_init(|| {
109 let global = self.owner_window();
110 CSSStyleDeclaration::new(
111 &global,
112 CSSStyleOwner::Element(Dom::from_ref(self.upcast())),
113 None,
114 CSSModificationAccess::ReadWrite,
115 CanGc::note(),
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, value: DOMString) {
130 self.as_element()
131 .update_nonce_internal_slot(value.to_string())
132 }
133
134 fn Autofocus(&self) -> bool {
136 self.element.has_attribute(&local_name!("autofocus"))
137 }
138
139 fn SetAutofocus(&self, autofocus: bool, can_gc: CanGc) {
141 self.element
142 .set_bool_attribute(&local_name!("autofocus"), autofocus, can_gc);
143 }
144
145 fn Focus(&self, cx: &mut js::context::JSContext, options: &FocusOptions) {
147 if !self
152 .upcast::<Node>()
153 .run_the_focusing_steps(None, CanGc::from_cx(cx))
154 {
155 return;
159 }
160
161 if !options.preventScroll {
169 let scroll_axis = ScrollAxisState {
170 position: ScrollLogicalPosition::Center,
171 requirement: ScrollRequirement::IfNotVisible,
172 };
173 self.upcast::<Element>().scroll_into_view_with_options(
174 ScrollBehavior::Smooth,
175 scroll_axis,
176 scroll_axis,
177 None,
178 None,
179 );
180 }
181 }
182
183 fn Blur(&self, cx: &mut js::context::JSContext) {
185 if !self.as_element().focus_state() {
188 return;
189 }
190 self.owner_document().focus_handler().focus(
192 FocusOperation::Focus(FocusableArea::Viewport),
193 FocusInitiator::Local,
194 CanGc::from_cx(cx),
195 );
196 }
197
198 fn TabIndex(&self) -> i32 {
200 self.element.tab_index()
201 }
202
203 fn SetTabIndex(&self, tab_index: i32, can_gc: CanGc) {
205 self.element
206 .set_int_attribute(&local_name!("tabindex"), tab_index, can_gc);
207 }
208}