script/dom/
virtualmethods.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 html5ever::LocalName;
6use script_bindings::script_runtime::CanGc;
7use style::attr::AttrValue;
8
9use crate::dom::attr::Attr;
10use crate::dom::bindings::inheritance::{
11    Castable, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId,
12    NodeTypeId, SVGElementTypeId, SVGGraphicsElementTypeId,
13};
14use crate::dom::bindings::str::DOMString;
15use crate::dom::document::Document;
16use crate::dom::documentfragment::DocumentFragment;
17use crate::dom::element::{AttributeMutation, Element};
18use crate::dom::event::Event;
19use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
20use crate::dom::html::htmlareaelement::HTMLAreaElement;
21use crate::dom::html::htmlbaseelement::HTMLBaseElement;
22use crate::dom::html::htmlbodyelement::HTMLBodyElement;
23use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
24use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
25use crate::dom::html::htmldetailselement::HTMLDetailsElement;
26use crate::dom::html::htmlelement::HTMLElement;
27use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
28use crate::dom::html::htmlfontelement::HTMLFontElement;
29use crate::dom::html::htmlformelement::HTMLFormElement;
30use crate::dom::html::htmlheadelement::HTMLHeadElement;
31use crate::dom::html::htmlhrelement::HTMLHRElement;
32use crate::dom::html::htmliframeelement::HTMLIFrameElement;
33use crate::dom::html::htmlimageelement::HTMLImageElement;
34use crate::dom::html::htmlinputelement::HTMLInputElement;
35use crate::dom::html::htmllabelelement::HTMLLabelElement;
36use crate::dom::html::htmllielement::HTMLLIElement;
37use crate::dom::html::htmllinkelement::HTMLLinkElement;
38use crate::dom::html::htmlmediaelement::HTMLMediaElement;
39use crate::dom::html::htmlmetaelement::HTMLMetaElement;
40use crate::dom::html::htmlmeterelement::HTMLMeterElement;
41use crate::dom::html::htmlobjectelement::HTMLObjectElement;
42use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
43use crate::dom::html::htmloptionelement::HTMLOptionElement;
44use crate::dom::html::htmloutputelement::HTMLOutputElement;
45use crate::dom::html::htmlpreelement::HTMLPreElement;
46use crate::dom::html::htmlprogresselement::HTMLProgressElement;
47use crate::dom::html::htmlscriptelement::HTMLScriptElement;
48use crate::dom::html::htmlselectelement::HTMLSelectElement;
49use crate::dom::html::htmlslotelement::HTMLSlotElement;
50use crate::dom::html::htmlsourceelement::HTMLSourceElement;
51use crate::dom::html::htmlstyleelement::HTMLStyleElement;
52use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
53use crate::dom::html::htmltablecolelement::HTMLTableColElement;
54use crate::dom::html::htmltableelement::HTMLTableElement;
55use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
56use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
57use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
58use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
59use crate::dom::html::htmltitleelement::HTMLTitleElement;
60use crate::dom::html::htmlvideoelement::HTMLVideoElement;
61use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext};
62use crate::dom::shadowroot::ShadowRoot;
63use crate::dom::svg::svgelement::SVGElement;
64use crate::dom::svg::svgimageelement::SVGImageElement;
65use crate::dom::svg::svgsvgelement::SVGSVGElement;
66
67/// Trait to allow DOM nodes to opt-in to overriding (or adding to) common
68/// behaviours. Replicates the effect of C++ virtual methods.
69pub(crate) trait VirtualMethods {
70    /// Returns self as the superclass of the implementation for this trait,
71    /// if any.
72    fn super_type(&self) -> Option<&dyn VirtualMethods>;
73
74    /// Called when attributes of a node are mutated.
75    /// <https://dom.spec.whatwg.org/#attribute-is-set>
76    /// <https://dom.spec.whatwg.org/#attribute-is-removed>
77    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
78        if let Some(s) = self.super_type() {
79            s.attribute_mutated(attr, mutation, can_gc);
80        }
81    }
82
83    /// Returns `true` if given attribute `attr` affects style of the
84    /// given element.
85    fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
86        match self.super_type() {
87            Some(s) => s.attribute_affects_presentational_hints(attr),
88            None => false,
89        }
90    }
91
92    /// Returns the right AttrValue variant for the attribute with name `name`
93    /// on this element.
94    fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
95        match self.super_type() {
96            Some(s) => s.parse_plain_attribute(name, value),
97            _ => AttrValue::String(value.into()),
98        }
99    }
100
101    /// Invoked during a DOM tree mutation after a node becomes connected, once all
102    /// related DOM tree mutations have been applied.
103    /// <https://dom.spec.whatwg.org/#concept-node-post-connection-ext>
104    fn post_connection_steps(&self, can_gc: CanGc) {
105        if let Some(s) = self.super_type() {
106            s.post_connection_steps(can_gc);
107        }
108    }
109
110    /// Called when a Node is appended to a tree.
111    fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
112        if let Some(s) = self.super_type() {
113            s.bind_to_tree(context, can_gc);
114        }
115    }
116
117    /// Called when a Node is removed from a tree.
118    /// Implements removing steps:
119    /// <https://dom.spec.whatwg.org/#concept-node-remove-ext>
120    fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
121        if let Some(s) = self.super_type() {
122            s.unbind_from_tree(context, can_gc);
123        }
124    }
125
126    /// Called on the parent when its children are changed.
127    fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
128        if let Some(s) = self.super_type() {
129            s.children_changed(mutation, can_gc);
130        }
131    }
132
133    /// Called during event dispatch after the bubbling phase completes.
134    fn handle_event(&self, event: &Event, can_gc: CanGc) {
135        if let Some(s) = self.super_type() {
136            s.handle_event(event, can_gc);
137        }
138    }
139
140    /// <https://dom.spec.whatwg.org/#concept-node-adopt-ext>
141    fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
142        if let Some(s) = self.super_type() {
143            s.adopting_steps(old_doc, can_gc);
144        }
145    }
146
147    /// <https://dom.spec.whatwg.org/#concept-node-clone-ext>
148    fn cloning_steps(
149        &self,
150        copy: &Node,
151        maybe_doc: Option<&Document>,
152        clone_children: CloneChildrenFlag,
153        can_gc: CanGc,
154    ) {
155        if let Some(s) = self.super_type() {
156            s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
157        }
158    }
159
160    /// Called on an element when it is popped off the stack of open elements
161    /// of a parser.
162    fn pop(&self) {
163        if let Some(s) = self.super_type() {
164            s.pop();
165        }
166    }
167}
168
169/// Obtain a VirtualMethods instance for a given Node-derived object. Any
170/// method call on the trait object will invoke the corresponding method on the
171/// concrete type, propagating up the parent hierarchy unless otherwise
172/// interrupted.
173pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
174    match node.type_id() {
175        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => {
176            node.downcast::<HTMLAnchorElement>().unwrap() as &dyn VirtualMethods
177        },
178        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
179            node.downcast::<HTMLAreaElement>().unwrap() as &dyn VirtualMethods
180        },
181        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBaseElement)) => {
182            node.downcast::<HTMLBaseElement>().unwrap() as &dyn VirtualMethods
183        },
184        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) => {
185            node.downcast::<HTMLBodyElement>().unwrap() as &dyn VirtualMethods
186        },
187        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
188            node.downcast::<HTMLButtonElement>().unwrap() as &dyn VirtualMethods
189        },
190        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)) => {
191            node.downcast::<HTMLCanvasElement>().unwrap() as &dyn VirtualMethods
192        },
193        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDetailsElement)) => {
194            node.downcast::<HTMLDetailsElement>().unwrap() as &dyn VirtualMethods
195        },
196        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => {
197            node.downcast::<HTMLFieldSetElement>().unwrap() as &dyn VirtualMethods
198        },
199        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFontElement)) => {
200            node.downcast::<HTMLFontElement>().unwrap() as &dyn VirtualMethods
201        },
202        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFormElement)) => {
203            node.downcast::<HTMLFormElement>().unwrap() as &dyn VirtualMethods
204        },
205        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHeadElement)) => {
206            node.downcast::<HTMLHeadElement>().unwrap() as &dyn VirtualMethods
207        },
208        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHRElement)) => {
209            node.downcast::<HTMLHRElement>().unwrap() as &dyn VirtualMethods
210        },
211        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement)) => {
212            node.downcast::<HTMLImageElement>().unwrap() as &dyn VirtualMethods
213        },
214        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement)) => {
215            node.downcast::<HTMLIFrameElement>().unwrap() as &dyn VirtualMethods
216        },
217        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
218            node.downcast::<HTMLInputElement>().unwrap() as &dyn VirtualMethods
219        },
220        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
221            node.downcast::<HTMLLabelElement>().unwrap() as &dyn VirtualMethods
222        },
223        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => {
224            node.downcast::<HTMLLIElement>().unwrap() as &dyn VirtualMethods
225        },
226        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
227            node.downcast::<HTMLLinkElement>().unwrap() as &dyn VirtualMethods
228        },
229        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(
230            media_el,
231        ))) => match media_el {
232            HTMLMediaElementTypeId::HTMLVideoElement => {
233                node.downcast::<HTMLVideoElement>().unwrap() as &dyn VirtualMethods
234            },
235            _ => node.downcast::<HTMLMediaElement>().unwrap() as &dyn VirtualMethods,
236        },
237        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMetaElement)) => {
238            node.downcast::<HTMLMetaElement>().unwrap() as &dyn VirtualMethods
239        },
240        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMeterElement)) => {
241            node.downcast::<HTMLMeterElement>().unwrap() as &dyn VirtualMethods
242        },
243        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
244            node.downcast::<HTMLObjectElement>().unwrap() as &dyn VirtualMethods
245        },
246        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement)) => {
247            node.downcast::<HTMLOptGroupElement>().unwrap() as &dyn VirtualMethods
248        },
249        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => {
250            node.downcast::<HTMLOptionElement>().unwrap() as &dyn VirtualMethods
251        },
252        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOutputElement)) => {
253            node.downcast::<HTMLOutputElement>().unwrap() as &dyn VirtualMethods
254        },
255        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement)) => {
256            node.downcast::<HTMLPreElement>().unwrap() as &dyn VirtualMethods
257        },
258        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLProgressElement)) => {
259            node.downcast::<HTMLProgressElement>().unwrap() as &dyn VirtualMethods
260        },
261        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLScriptElement)) => {
262            node.downcast::<HTMLScriptElement>().unwrap() as &dyn VirtualMethods
263        },
264        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) => {
265            node.downcast::<HTMLSelectElement>().unwrap() as &dyn VirtualMethods
266        },
267        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSourceElement)) => {
268            node.downcast::<HTMLSourceElement>().unwrap() as &dyn VirtualMethods
269        },
270        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSlotElement)) => {
271            node.downcast::<HTMLSlotElement>().unwrap() as &dyn VirtualMethods
272        },
273        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLStyleElement)) => {
274            node.downcast::<HTMLStyleElement>().unwrap() as &dyn VirtualMethods
275        },
276        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement)) => {
277            node.downcast::<HTMLTableElement>().unwrap() as &dyn VirtualMethods
278        },
279        NodeTypeId::Element(ElementTypeId::HTMLElement(
280            HTMLElementTypeId::HTMLTableCellElement,
281        )) => node.downcast::<HTMLTableCellElement>().unwrap() as &dyn VirtualMethods,
282        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement)) => {
283            node.downcast::<HTMLTableColElement>().unwrap() as &dyn VirtualMethods
284        },
285        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement)) => {
286            node.downcast::<HTMLTableRowElement>().unwrap() as &dyn VirtualMethods
287        },
288        NodeTypeId::Element(ElementTypeId::HTMLElement(
289            HTMLElementTypeId::HTMLTableSectionElement,
290        )) => node.downcast::<HTMLTableSectionElement>().unwrap() as &dyn VirtualMethods,
291        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTemplateElement)) => {
292            node.downcast::<HTMLTemplateElement>().unwrap() as &dyn VirtualMethods
293        },
294        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
295            node.downcast::<HTMLTextAreaElement>().unwrap() as &dyn VirtualMethods
296        },
297        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
298            node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
299        },
300        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
301            SVGGraphicsElementTypeId::SVGImageElement,
302        ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
303        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
304            SVGGraphicsElementTypeId::SVGSVGElement,
305        ))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
306        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => {
307            node.downcast::<SVGElement>().unwrap() as &dyn VirtualMethods
308        },
309        NodeTypeId::Element(ElementTypeId::Element) => {
310            node.downcast::<Element>().unwrap() as &dyn VirtualMethods
311        },
312        NodeTypeId::Element(_) => node.downcast::<HTMLElement>().unwrap() as &dyn VirtualMethods,
313        NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => {
314            node.downcast::<ShadowRoot>().unwrap() as &dyn VirtualMethods
315        },
316        NodeTypeId::DocumentFragment(_) => {
317            node.downcast::<DocumentFragment>().unwrap() as &dyn VirtualMethods
318        },
319        _ => node as &dyn VirtualMethods,
320    }
321}