1use html5ever::LocalName;
6use js::context::JSContext;
7use script_bindings::root::DomRoot;
8use script_bindings::script_runtime::CanGc;
9use style::attr::AttrValue;
10
11use crate::dom::attr::Attr;
12use crate::dom::bindings::inheritance::{
13 Castable, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId,
14 NodeTypeId, SVGElementTypeId, SVGGraphicsElementTypeId,
15};
16use crate::dom::bindings::str::DOMString;
17use crate::dom::document::Document;
18use crate::dom::documentfragment::DocumentFragment;
19use crate::dom::element::{AttributeMutation, Element};
20use crate::dom::event::Event;
21use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
22use crate::dom::html::htmlareaelement::HTMLAreaElement;
23use crate::dom::html::htmlbaseelement::HTMLBaseElement;
24use crate::dom::html::htmlbodyelement::HTMLBodyElement;
25use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
26use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
27use crate::dom::html::htmldetailselement::HTMLDetailsElement;
28use crate::dom::html::htmlelement::HTMLElement;
29use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
30use crate::dom::html::htmlfontelement::HTMLFontElement;
31use crate::dom::html::htmlformelement::HTMLFormElement;
32use crate::dom::html::htmlheadelement::HTMLHeadElement;
33use crate::dom::html::htmlhrelement::HTMLHRElement;
34use crate::dom::html::htmliframeelement::HTMLIFrameElement;
35use crate::dom::html::htmlimageelement::HTMLImageElement;
36use crate::dom::html::htmlinputelement::HTMLInputElement;
37use crate::dom::html::htmllabelelement::HTMLLabelElement;
38use crate::dom::html::htmllielement::HTMLLIElement;
39use crate::dom::html::htmllinkelement::HTMLLinkElement;
40use crate::dom::html::htmlmediaelement::HTMLMediaElement;
41use crate::dom::html::htmlmetaelement::HTMLMetaElement;
42use crate::dom::html::htmlmeterelement::HTMLMeterElement;
43use crate::dom::html::htmlobjectelement::HTMLObjectElement;
44use crate::dom::html::htmloptgroupelement::HTMLOptGroupElement;
45use crate::dom::html::htmloptionelement::HTMLOptionElement;
46use crate::dom::html::htmloutputelement::HTMLOutputElement;
47use crate::dom::html::htmlpreelement::HTMLPreElement;
48use crate::dom::html::htmlprogresselement::HTMLProgressElement;
49use crate::dom::html::htmlscriptelement::HTMLScriptElement;
50use crate::dom::html::htmlselectelement::HTMLSelectElement;
51use crate::dom::html::htmlslotelement::HTMLSlotElement;
52use crate::dom::html::htmlsourceelement::HTMLSourceElement;
53use crate::dom::html::htmlstyleelement::HTMLStyleElement;
54use crate::dom::html::htmltablecellelement::HTMLTableCellElement;
55use crate::dom::html::htmltablecolelement::HTMLTableColElement;
56use crate::dom::html::htmltableelement::HTMLTableElement;
57use crate::dom::html::htmltablerowelement::HTMLTableRowElement;
58use crate::dom::html::htmltablesectionelement::HTMLTableSectionElement;
59use crate::dom::html::htmltemplateelement::HTMLTemplateElement;
60use crate::dom::html::htmltextareaelement::HTMLTextAreaElement;
61use crate::dom::html::htmltitleelement::HTMLTitleElement;
62use crate::dom::html::htmlvideoelement::HTMLVideoElement;
63use crate::dom::htmlbuttonelement::CommandState;
64use crate::dom::htmldialogelement::HTMLDialogElement;
65use crate::dom::node::{BindContext, ChildrenMutation, CloneChildrenFlag, Node, UnbindContext};
66use crate::dom::shadowroot::ShadowRoot;
67use crate::dom::svg::svgelement::SVGElement;
68use crate::dom::svg::svgimageelement::SVGImageElement;
69use crate::dom::svg::svgsvgelement::SVGSVGElement;
70
71pub(crate) trait VirtualMethods {
74 fn super_type(&self) -> Option<&dyn VirtualMethods>;
77
78 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, can_gc: CanGc) {
82 if let Some(s) = self.super_type() {
83 s.attribute_mutated(attr, mutation, can_gc);
84 }
85 }
86
87 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
90 match self.super_type() {
91 Some(s) => s.attribute_affects_presentational_hints(attr),
92 None => false,
93 }
94 }
95
96 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
99 match self.super_type() {
100 Some(s) => s.parse_plain_attribute(name, value),
101 _ => AttrValue::String(value.into()),
102 }
103 }
104
105 fn post_connection_steps(&self, cx: &mut JSContext) {
109 if let Some(s) = self.super_type() {
110 s.post_connection_steps(cx);
111 }
112 }
113
114 fn bind_to_tree(&self, context: &BindContext, can_gc: CanGc) {
116 if let Some(s) = self.super_type() {
117 s.bind_to_tree(context, can_gc);
118 }
119 }
120
121 fn unbind_from_tree(&self, context: &UnbindContext, can_gc: CanGc) {
125 if let Some(s) = self.super_type() {
126 s.unbind_from_tree(context, can_gc);
127 }
128 }
129
130 fn children_changed(&self, mutation: &ChildrenMutation, can_gc: CanGc) {
132 if let Some(s) = self.super_type() {
133 s.children_changed(mutation, can_gc);
134 }
135 }
136
137 fn handle_event(&self, event: &Event, can_gc: CanGc) {
139 if let Some(s) = self.super_type() {
140 s.handle_event(event, can_gc);
141 }
142 }
143
144 fn is_valid_command_steps(&self, command: CommandState) -> bool {
146 self.super_type()
147 .is_some_and(|super_type| super_type.is_valid_command_steps(command))
148 }
149
150 fn command_steps(
152 &self,
153 button: DomRoot<HTMLButtonElement>,
154 command: CommandState,
155 can_gc: CanGc,
156 ) -> bool {
157 self.super_type()
158 .is_some_and(|super_type| super_type.command_steps(button, command, can_gc))
159 }
160
161 fn adopting_steps(&self, old_doc: &Document, can_gc: CanGc) {
163 if let Some(s) = self.super_type() {
164 s.adopting_steps(old_doc, can_gc);
165 }
166 }
167
168 fn cloning_steps(
170 &self,
171 copy: &Node,
172 maybe_doc: Option<&Document>,
173 clone_children: CloneChildrenFlag,
174 can_gc: CanGc,
175 ) {
176 if let Some(s) = self.super_type() {
177 s.cloning_steps(copy, maybe_doc, clone_children, can_gc);
178 }
179 }
180
181 fn pop(&self) {
184 if let Some(s) = self.super_type() {
185 s.pop();
186 }
187 }
188}
189
190pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
195 match node.type_id() {
196 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => {
197 node.downcast::<HTMLAnchorElement>().unwrap() as &dyn VirtualMethods
198 },
199 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
200 node.downcast::<HTMLAreaElement>().unwrap() as &dyn VirtualMethods
201 },
202 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBaseElement)) => {
203 node.downcast::<HTMLBaseElement>().unwrap() as &dyn VirtualMethods
204 },
205 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) => {
206 node.downcast::<HTMLBodyElement>().unwrap() as &dyn VirtualMethods
207 },
208 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
209 node.downcast::<HTMLButtonElement>().unwrap() as &dyn VirtualMethods
210 },
211 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)) => {
212 node.downcast::<HTMLCanvasElement>().unwrap() as &dyn VirtualMethods
213 },
214 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDetailsElement)) => {
215 node.downcast::<HTMLDetailsElement>().unwrap() as &dyn VirtualMethods
216 },
217 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDialogElement)) => {
218 node.downcast::<HTMLDialogElement>().unwrap() as &dyn VirtualMethods
219 },
220 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => {
221 node.downcast::<HTMLFieldSetElement>().unwrap() as &dyn VirtualMethods
222 },
223 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFontElement)) => {
224 node.downcast::<HTMLFontElement>().unwrap() as &dyn VirtualMethods
225 },
226 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFormElement)) => {
227 node.downcast::<HTMLFormElement>().unwrap() as &dyn VirtualMethods
228 },
229 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHeadElement)) => {
230 node.downcast::<HTMLHeadElement>().unwrap() as &dyn VirtualMethods
231 },
232 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHRElement)) => {
233 node.downcast::<HTMLHRElement>().unwrap() as &dyn VirtualMethods
234 },
235 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement)) => {
236 node.downcast::<HTMLImageElement>().unwrap() as &dyn VirtualMethods
237 },
238 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement)) => {
239 node.downcast::<HTMLIFrameElement>().unwrap() as &dyn VirtualMethods
240 },
241 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
242 node.downcast::<HTMLInputElement>().unwrap() as &dyn VirtualMethods
243 },
244 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
245 node.downcast::<HTMLLabelElement>().unwrap() as &dyn VirtualMethods
246 },
247 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => {
248 node.downcast::<HTMLLIElement>().unwrap() as &dyn VirtualMethods
249 },
250 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
251 node.downcast::<HTMLLinkElement>().unwrap() as &dyn VirtualMethods
252 },
253 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(
254 media_el,
255 ))) => match media_el {
256 HTMLMediaElementTypeId::HTMLVideoElement => {
257 node.downcast::<HTMLVideoElement>().unwrap() as &dyn VirtualMethods
258 },
259 _ => node.downcast::<HTMLMediaElement>().unwrap() as &dyn VirtualMethods,
260 },
261 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMetaElement)) => {
262 node.downcast::<HTMLMetaElement>().unwrap() as &dyn VirtualMethods
263 },
264 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMeterElement)) => {
265 node.downcast::<HTMLMeterElement>().unwrap() as &dyn VirtualMethods
266 },
267 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
268 node.downcast::<HTMLObjectElement>().unwrap() as &dyn VirtualMethods
269 },
270 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement)) => {
271 node.downcast::<HTMLOptGroupElement>().unwrap() as &dyn VirtualMethods
272 },
273 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => {
274 node.downcast::<HTMLOptionElement>().unwrap() as &dyn VirtualMethods
275 },
276 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOutputElement)) => {
277 node.downcast::<HTMLOutputElement>().unwrap() as &dyn VirtualMethods
278 },
279 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement)) => {
280 node.downcast::<HTMLPreElement>().unwrap() as &dyn VirtualMethods
281 },
282 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLProgressElement)) => {
283 node.downcast::<HTMLProgressElement>().unwrap() as &dyn VirtualMethods
284 },
285 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLScriptElement)) => {
286 node.downcast::<HTMLScriptElement>().unwrap() as &dyn VirtualMethods
287 },
288 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) => {
289 node.downcast::<HTMLSelectElement>().unwrap() as &dyn VirtualMethods
290 },
291 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSourceElement)) => {
292 node.downcast::<HTMLSourceElement>().unwrap() as &dyn VirtualMethods
293 },
294 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSlotElement)) => {
295 node.downcast::<HTMLSlotElement>().unwrap() as &dyn VirtualMethods
296 },
297 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLStyleElement)) => {
298 node.downcast::<HTMLStyleElement>().unwrap() as &dyn VirtualMethods
299 },
300 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement)) => {
301 node.downcast::<HTMLTableElement>().unwrap() as &dyn VirtualMethods
302 },
303 NodeTypeId::Element(ElementTypeId::HTMLElement(
304 HTMLElementTypeId::HTMLTableCellElement,
305 )) => node.downcast::<HTMLTableCellElement>().unwrap() as &dyn VirtualMethods,
306 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement)) => {
307 node.downcast::<HTMLTableColElement>().unwrap() as &dyn VirtualMethods
308 },
309 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement)) => {
310 node.downcast::<HTMLTableRowElement>().unwrap() as &dyn VirtualMethods
311 },
312 NodeTypeId::Element(ElementTypeId::HTMLElement(
313 HTMLElementTypeId::HTMLTableSectionElement,
314 )) => node.downcast::<HTMLTableSectionElement>().unwrap() as &dyn VirtualMethods,
315 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTemplateElement)) => {
316 node.downcast::<HTMLTemplateElement>().unwrap() as &dyn VirtualMethods
317 },
318 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
319 node.downcast::<HTMLTextAreaElement>().unwrap() as &dyn VirtualMethods
320 },
321 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
322 node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
323 },
324 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
325 SVGGraphicsElementTypeId::SVGImageElement,
326 ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
327 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
328 SVGGraphicsElementTypeId::SVGSVGElement,
329 ))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
330 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => {
331 node.downcast::<SVGElement>().unwrap() as &dyn VirtualMethods
332 },
333 NodeTypeId::Element(ElementTypeId::Element) => {
334 node.downcast::<Element>().unwrap() as &dyn VirtualMethods
335 },
336 NodeTypeId::Element(_) => node.downcast::<HTMLElement>().unwrap() as &dyn VirtualMethods,
337 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => {
338 node.downcast::<ShadowRoot>().unwrap() as &dyn VirtualMethods
339 },
340 NodeTypeId::DocumentFragment(_) => {
341 node.downcast::<DocumentFragment>().unwrap() as &dyn VirtualMethods
342 },
343 _ => node as &dyn VirtualMethods,
344 }
345}