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::svgelement::SVGElement;
64use crate::dom::svgimageelement::SVGImageElement;
65use crate::dom::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) {
105        if let Some(s) = self.super_type() {
106            s.post_connection_steps();
107        }
108    }
109
110    /// Called when a Node is appended to a tree, where 'tree_connected' indicates
111    /// whether the tree is part of a Document.
112    fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
113        if let Some(s) = self.super_type() {
114            s.bind_to_tree(context, can_gc);
115        }
116    }
117
118    /// Called when a Node is removed from a tree, where 'tree_connected'
119    /// indicates whether the tree is part of a Document.
120    /// Implements removing steps:
121    /// <https://dom.spec.whatwg.org/#concept-node-remove-ext>
122    fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
123        if let Some(s) = self.super_type() {
124            s.unbind_from_tree(context, can_gc);
125        }
126    }
127
128    /// Called on the parent when its children are changed.
129    fn children_changed(&self, mutation: &ChildrenMutation) {
130        if let Some(s) = self.super_type() {
131            s.children_changed(mutation);
132        }
133    }
134
135    /// Called during event dispatch after the bubbling phase completes.
136    fn handle_event(&self, event: &Event, can_gc: CanGc) {
137        if let Some(s) = self.super_type() {
138            s.handle_event(event, can_gc);
139        }
140    }
141
142    /// <https://dom.spec.whatwg.org/#concept-node-adopt-ext>
143    fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
144        if let Some(s) = self.super_type() {
145            s.adopting_steps(old_doc, can_gc);
146        }
147    }
148
149    /// <https://dom.spec.whatwg.org/#concept-node-clone-ext>
150    fn cloning_steps(
151        &self,
152        copy: &Node,
153        maybe_doc: Option<&Document>,
154        clone_children: CloneChildrenFlag,
155        can_gc: CanGc,
156    ) {
157        if let Some(s) = self.super_type() {
158            s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
159        }
160    }
161
162    /// Called on an element when it is popped off the stack of open elements
163    /// of a parser.
164    fn pop(&self) {
165        if let Some(s) = self.super_type() {
166            s.pop();
167        }
168    }
169}
170
171/// Obtain a VirtualMethods instance for a given Node-derived object. Any
172/// method call on the trait object will invoke the corresponding method on the
173/// concrete type, propagating up the parent hierarchy unless otherwise
174/// interrupted.
175pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
176    match node.type_id() {
177        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => {
178            node.downcast::<HTMLAnchorElement>().unwrap() as &dyn VirtualMethods
179        },
180        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
181            node.downcast::<HTMLAreaElement>().unwrap() as &dyn VirtualMethods
182        },
183        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBaseElement)) => {
184            node.downcast::<HTMLBaseElement>().unwrap() as &dyn VirtualMethods
185        },
186        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) => {
187            node.downcast::<HTMLBodyElement>().unwrap() as &dyn VirtualMethods
188        },
189        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
190            node.downcast::<HTMLButtonElement>().unwrap() as &dyn VirtualMethods
191        },
192        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)) => {
193            node.downcast::<HTMLCanvasElement>().unwrap() as &dyn VirtualMethods
194        },
195        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDetailsElement)) => {
196            node.downcast::<HTMLDetailsElement>().unwrap() as &dyn VirtualMethods
197        },
198        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => {
199            node.downcast::<HTMLFieldSetElement>().unwrap() as &dyn VirtualMethods
200        },
201        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFontElement)) => {
202            node.downcast::<HTMLFontElement>().unwrap() as &dyn VirtualMethods
203        },
204        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFormElement)) => {
205            node.downcast::<HTMLFormElement>().unwrap() as &dyn VirtualMethods
206        },
207        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHeadElement)) => {
208            node.downcast::<HTMLHeadElement>().unwrap() as &dyn VirtualMethods
209        },
210        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHRElement)) => {
211            node.downcast::<HTMLHRElement>().unwrap() as &dyn VirtualMethods
212        },
213        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement)) => {
214            node.downcast::<HTMLImageElement>().unwrap() as &dyn VirtualMethods
215        },
216        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement)) => {
217            node.downcast::<HTMLIFrameElement>().unwrap() as &dyn VirtualMethods
218        },
219        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
220            node.downcast::<HTMLInputElement>().unwrap() as &dyn VirtualMethods
221        },
222        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
223            node.downcast::<HTMLLabelElement>().unwrap() as &dyn VirtualMethods
224        },
225        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => {
226            node.downcast::<HTMLLIElement>().unwrap() as &dyn VirtualMethods
227        },
228        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
229            node.downcast::<HTMLLinkElement>().unwrap() as &dyn VirtualMethods
230        },
231        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(
232            media_el,
233        ))) => match media_el {
234            HTMLMediaElementTypeId::HTMLVideoElement => {
235                node.downcast::<HTMLVideoElement>().unwrap() as &dyn VirtualMethods
236            },
237            _ => node.downcast::<HTMLMediaElement>().unwrap() as &dyn VirtualMethods,
238        },
239        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMetaElement)) => {
240            node.downcast::<HTMLMetaElement>().unwrap() as &dyn VirtualMethods
241        },
242        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMeterElement)) => {
243            node.downcast::<HTMLMeterElement>().unwrap() as &dyn VirtualMethods
244        },
245        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
246            node.downcast::<HTMLObjectElement>().unwrap() as &dyn VirtualMethods
247        },
248        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement)) => {
249            node.downcast::<HTMLOptGroupElement>().unwrap() as &dyn VirtualMethods
250        },
251        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => {
252            node.downcast::<HTMLOptionElement>().unwrap() as &dyn VirtualMethods
253        },
254        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOutputElement)) => {
255            node.downcast::<HTMLOutputElement>().unwrap() as &dyn VirtualMethods
256        },
257        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement)) => {
258            node.downcast::<HTMLPreElement>().unwrap() as &dyn VirtualMethods
259        },
260        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLProgressElement)) => {
261            node.downcast::<HTMLProgressElement>().unwrap() as &dyn VirtualMethods
262        },
263        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLScriptElement)) => {
264            node.downcast::<HTMLScriptElement>().unwrap() as &dyn VirtualMethods
265        },
266        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) => {
267            node.downcast::<HTMLSelectElement>().unwrap() as &dyn VirtualMethods
268        },
269        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSourceElement)) => {
270            node.downcast::<HTMLSourceElement>().unwrap() as &dyn VirtualMethods
271        },
272        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSlotElement)) => {
273            node.downcast::<HTMLSlotElement>().unwrap() as &dyn VirtualMethods
274        },
275        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLStyleElement)) => {
276            node.downcast::<HTMLStyleElement>().unwrap() as &dyn VirtualMethods
277        },
278        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement)) => {
279            node.downcast::<HTMLTableElement>().unwrap() as &dyn VirtualMethods
280        },
281        NodeTypeId::Element(ElementTypeId::HTMLElement(
282            HTMLElementTypeId::HTMLTableCellElement,
283        )) => node.downcast::<HTMLTableCellElement>().unwrap() as &dyn VirtualMethods,
284        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement)) => {
285            node.downcast::<HTMLTableColElement>().unwrap() as &dyn VirtualMethods
286        },
287        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement)) => {
288            node.downcast::<HTMLTableRowElement>().unwrap() as &dyn VirtualMethods
289        },
290        NodeTypeId::Element(ElementTypeId::HTMLElement(
291            HTMLElementTypeId::HTMLTableSectionElement,
292        )) => node.downcast::<HTMLTableSectionElement>().unwrap() as &dyn VirtualMethods,
293        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTemplateElement)) => {
294            node.downcast::<HTMLTemplateElement>().unwrap() as &dyn VirtualMethods
295        },
296        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
297            node.downcast::<HTMLTextAreaElement>().unwrap() as &dyn VirtualMethods
298        },
299        NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
300            node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
301        },
302        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
303            SVGGraphicsElementTypeId::SVGImageElement,
304        ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
305        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
306            SVGGraphicsElementTypeId::SVGSVGElement,
307        ))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
308        NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => {
309            node.downcast::<SVGElement>().unwrap() as &dyn VirtualMethods
310        },
311        NodeTypeId::Element(ElementTypeId::Element) => {
312            node.downcast::<Element>().unwrap() as &dyn VirtualMethods
313        },
314        NodeTypeId::Element(_) => node.downcast::<HTMLElement>().unwrap() as &dyn VirtualMethods,
315        NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => {
316            node.downcast::<ShadowRoot>().unwrap() as &dyn VirtualMethods
317        },
318        NodeTypeId::DocumentFragment(_) => {
319            node.downcast::<DocumentFragment>().unwrap() as &dyn VirtualMethods
320        },
321        _ => node as &dyn VirtualMethods,
322    }
323}