script/dom/
svgelement.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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    /// <https://html.spec.whatwg.org/multipage/#the-style-attribute>
96    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    // https://html.spec.whatwg.org/multipage/#globaleventhandlers
110    global_event_handlers!();
111
112    /// <https://html.spec.whatwg.org/multipage/#dom-noncedelement-nonce>
113    fn Nonce(&self) -> DOMString {
114        self.as_element().nonce_value().into()
115    }
116
117    /// <https://html.spec.whatwg.org/multipage/#dom-noncedelement-nonce>
118    fn SetNonce(&self, value: DOMString) {
119        self.as_element()
120            .update_nonce_internal_slot(value.to_string())
121    }
122
123    /// <https://html.spec.whatwg.org/multipage/#dom-fe-autofocus>
124    fn Autofocus(&self) -> bool {
125        self.element.has_attribute(&local_name!("autofocus"))
126    }
127
128    /// <https://html.spec.whatwg.org/multipage/#dom-fe-autofocus>
129    fn SetAutofocus(&self, autofocus: bool, can_gc: CanGc) {
130        self.element
131            .set_bool_attribute(&local_name!("autofocus"), autofocus, can_gc);
132    }
133
134    /// <https://html.spec.whatwg.org/multipage/#dom-focus>
135    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}