1use html5ever::LocalName;
6use js::context::JSContext;
7use script_bindings::root::DomRoot;
8use style::attr::AttrValue;
9
10use crate::dom::attr::Attr;
11use crate::dom::bindings::inheritance::{
12 Castable, DocumentFragmentTypeId, ElementTypeId, HTMLElementTypeId, HTMLMediaElementTypeId,
13 NodeTypeId, SVGElementTypeId, SVGGraphicsElementTypeId,
14};
15use crate::dom::bindings::str::DOMString;
16use crate::dom::document::Document;
17use crate::dom::documentfragment::DocumentFragment;
18use crate::dom::element::{AttributeMutation, Element};
19use crate::dom::event::Event;
20use crate::dom::html::htmlanchorelement::HTMLAnchorElement;
21use crate::dom::html::htmlareaelement::HTMLAreaElement;
22use crate::dom::html::htmlbaseelement::HTMLBaseElement;
23use crate::dom::html::htmlbodyelement::HTMLBodyElement;
24use crate::dom::html::htmlbuttonelement::HTMLButtonElement;
25use crate::dom::html::htmlcanvaselement::HTMLCanvasElement;
26use crate::dom::html::htmldetailselement::HTMLDetailsElement;
27use crate::dom::html::htmlelement::HTMLElement;
28use crate::dom::html::htmlfieldsetelement::HTMLFieldSetElement;
29use crate::dom::html::htmlfontelement::HTMLFontElement;
30use crate::dom::html::htmlformelement::HTMLFormElement;
31use crate::dom::html::htmlheadelement::HTMLHeadElement;
32use crate::dom::html::htmlhrelement::HTMLHRElement;
33use crate::dom::html::htmliframeelement::HTMLIFrameElement;
34use crate::dom::html::htmlimageelement::HTMLImageElement;
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::html::input_element::HTMLInputElement;
62use crate::dom::htmlbuttonelement::CommandState;
63use crate::dom::htmldialogelement::HTMLDialogElement;
64use crate::dom::node::{
65 BindContext, ChildrenMutation, CloneChildrenFlag, MoveContext, Node, UnbindContext,
66};
67use crate::dom::shadowroot::ShadowRoot;
68use crate::dom::svg::svgelement::SVGElement;
69use crate::dom::svg::svgimageelement::SVGImageElement;
70use crate::dom::svg::svgsvgelement::SVGSVGElement;
71
72pub(crate) trait VirtualMethods {
75 fn super_type(&self) -> Option<&dyn VirtualMethods>;
78
79 fn attribute_mutated(
83 &self,
84 cx: &mut js::context::JSContext,
85 attr: &Attr,
86 mutation: AttributeMutation,
87 ) {
88 if let Some(s) = self.super_type() {
89 s.attribute_mutated(cx, attr, mutation);
90 }
91 }
92
93 fn attribute_affects_presentational_hints(&self, attr: &Attr) -> bool {
96 match self.super_type() {
97 Some(s) => s.attribute_affects_presentational_hints(attr),
98 None => false,
99 }
100 }
101
102 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
105 match self.super_type() {
106 Some(s) => s.parse_plain_attribute(name, value),
107 _ => AttrValue::String(value.into()),
108 }
109 }
110
111 fn post_connection_steps(&self, cx: &mut JSContext) {
115 if let Some(s) = self.super_type() {
116 s.post_connection_steps(cx);
117 }
118 }
119
120 fn moving_steps(&self, cx: &mut JSContext, context: &MoveContext) {
122 if let Some(s) = self.super_type() {
123 s.moving_steps(cx, context);
124 }
125 }
126
127 fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
129 if let Some(s) = self.super_type() {
130 s.bind_to_tree(cx, context);
131 }
132 }
133
134 fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
138 if let Some(s) = self.super_type() {
139 s.unbind_from_tree(cx, context);
140 }
141 }
142
143 fn children_changed(&self, cx: &mut JSContext, mutation: &ChildrenMutation) {
145 if let Some(s) = self.super_type() {
146 s.children_changed(cx, mutation);
147 }
148 }
149
150 fn handle_event(&self, cx: &mut js::context::JSContext, event: &Event) {
152 if let Some(s) = self.super_type() {
153 s.handle_event(cx, event);
154 }
155 }
156
157 fn is_valid_command_steps(&self, command: CommandState) -> bool {
159 self.super_type()
160 .is_some_and(|super_type| super_type.is_valid_command_steps(command))
161 }
162
163 fn command_steps(
165 &self,
166 cx: &mut js::context::JSContext,
167 button: DomRoot<HTMLButtonElement>,
168 command: CommandState,
169 ) -> bool {
170 self.super_type()
171 .is_some_and(|super_type| super_type.command_steps(cx, button, command))
172 }
173
174 fn adopting_steps(&self, cx: &mut JSContext, old_doc: &Document) {
176 if let Some(s) = self.super_type() {
177 s.adopting_steps(cx, old_doc);
178 }
179 }
180
181 fn cloning_steps(
183 &self,
184 cx: &mut JSContext,
185 copy: &Node,
186 maybe_doc: Option<&Document>,
187 clone_children: CloneChildrenFlag,
188 ) {
189 if let Some(s) = self.super_type() {
190 s.cloning_steps(cx, copy, maybe_doc, clone_children);
191 }
192 }
193
194 fn pop(&self) {
197 if let Some(s) = self.super_type() {
198 s.pop();
199 }
200 }
201}
202
203pub(crate) fn vtable_for(node: &Node) -> &dyn VirtualMethods {
208 match node.type_id() {
209 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAnchorElement)) => {
210 node.downcast::<HTMLAnchorElement>().unwrap() as &dyn VirtualMethods
211 },
212 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLAreaElement)) => {
213 node.downcast::<HTMLAreaElement>().unwrap() as &dyn VirtualMethods
214 },
215 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBaseElement)) => {
216 node.downcast::<HTMLBaseElement>().unwrap() as &dyn VirtualMethods
217 },
218 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLBodyElement)) => {
219 node.downcast::<HTMLBodyElement>().unwrap() as &dyn VirtualMethods
220 },
221 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLButtonElement)) => {
222 node.downcast::<HTMLButtonElement>().unwrap() as &dyn VirtualMethods
223 },
224 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement)) => {
225 node.downcast::<HTMLCanvasElement>().unwrap() as &dyn VirtualMethods
226 },
227 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDetailsElement)) => {
228 node.downcast::<HTMLDetailsElement>().unwrap() as &dyn VirtualMethods
229 },
230 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLDialogElement)) => {
231 node.downcast::<HTMLDialogElement>().unwrap() as &dyn VirtualMethods
232 },
233 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFieldSetElement)) => {
234 node.downcast::<HTMLFieldSetElement>().unwrap() as &dyn VirtualMethods
235 },
236 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFontElement)) => {
237 node.downcast::<HTMLFontElement>().unwrap() as &dyn VirtualMethods
238 },
239 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLFormElement)) => {
240 node.downcast::<HTMLFormElement>().unwrap() as &dyn VirtualMethods
241 },
242 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHeadElement)) => {
243 node.downcast::<HTMLHeadElement>().unwrap() as &dyn VirtualMethods
244 },
245 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHRElement)) => {
246 node.downcast::<HTMLHRElement>().unwrap() as &dyn VirtualMethods
247 },
248 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement)) => {
249 node.downcast::<HTMLImageElement>().unwrap() as &dyn VirtualMethods
250 },
251 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLIFrameElement)) => {
252 node.downcast::<HTMLIFrameElement>().unwrap() as &dyn VirtualMethods
253 },
254 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLInputElement)) => {
255 node.downcast::<HTMLInputElement>().unwrap() as &dyn VirtualMethods
256 },
257 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLabelElement)) => {
258 node.downcast::<HTMLLabelElement>().unwrap() as &dyn VirtualMethods
259 },
260 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLIElement)) => {
261 node.downcast::<HTMLLIElement>().unwrap() as &dyn VirtualMethods
262 },
263 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLLinkElement)) => {
264 node.downcast::<HTMLLinkElement>().unwrap() as &dyn VirtualMethods
265 },
266 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMediaElement(
267 media_el,
268 ))) => match media_el {
269 HTMLMediaElementTypeId::HTMLVideoElement => {
270 node.downcast::<HTMLVideoElement>().unwrap() as &dyn VirtualMethods
271 },
272 _ => node.downcast::<HTMLMediaElement>().unwrap() as &dyn VirtualMethods,
273 },
274 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMetaElement)) => {
275 node.downcast::<HTMLMetaElement>().unwrap() as &dyn VirtualMethods
276 },
277 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLMeterElement)) => {
278 node.downcast::<HTMLMeterElement>().unwrap() as &dyn VirtualMethods
279 },
280 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement)) => {
281 node.downcast::<HTMLObjectElement>().unwrap() as &dyn VirtualMethods
282 },
283 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptGroupElement)) => {
284 node.downcast::<HTMLOptGroupElement>().unwrap() as &dyn VirtualMethods
285 },
286 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOptionElement)) => {
287 node.downcast::<HTMLOptionElement>().unwrap() as &dyn VirtualMethods
288 },
289 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLOutputElement)) => {
290 node.downcast::<HTMLOutputElement>().unwrap() as &dyn VirtualMethods
291 },
292 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLPreElement)) => {
293 node.downcast::<HTMLPreElement>().unwrap() as &dyn VirtualMethods
294 },
295 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLProgressElement)) => {
296 node.downcast::<HTMLProgressElement>().unwrap() as &dyn VirtualMethods
297 },
298 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLScriptElement)) => {
299 node.downcast::<HTMLScriptElement>().unwrap() as &dyn VirtualMethods
300 },
301 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSelectElement)) => {
302 node.downcast::<HTMLSelectElement>().unwrap() as &dyn VirtualMethods
303 },
304 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSourceElement)) => {
305 node.downcast::<HTMLSourceElement>().unwrap() as &dyn VirtualMethods
306 },
307 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLSlotElement)) => {
308 node.downcast::<HTMLSlotElement>().unwrap() as &dyn VirtualMethods
309 },
310 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLStyleElement)) => {
311 node.downcast::<HTMLStyleElement>().unwrap() as &dyn VirtualMethods
312 },
313 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableElement)) => {
314 node.downcast::<HTMLTableElement>().unwrap() as &dyn VirtualMethods
315 },
316 NodeTypeId::Element(ElementTypeId::HTMLElement(
317 HTMLElementTypeId::HTMLTableCellElement,
318 )) => node.downcast::<HTMLTableCellElement>().unwrap() as &dyn VirtualMethods,
319 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableColElement)) => {
320 node.downcast::<HTMLTableColElement>().unwrap() as &dyn VirtualMethods
321 },
322 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement)) => {
323 node.downcast::<HTMLTableRowElement>().unwrap() as &dyn VirtualMethods
324 },
325 NodeTypeId::Element(ElementTypeId::HTMLElement(
326 HTMLElementTypeId::HTMLTableSectionElement,
327 )) => node.downcast::<HTMLTableSectionElement>().unwrap() as &dyn VirtualMethods,
328 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTemplateElement)) => {
329 node.downcast::<HTMLTemplateElement>().unwrap() as &dyn VirtualMethods
330 },
331 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTextAreaElement)) => {
332 node.downcast::<HTMLTextAreaElement>().unwrap() as &dyn VirtualMethods
333 },
334 NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTitleElement)) => {
335 node.downcast::<HTMLTitleElement>().unwrap() as &dyn VirtualMethods
336 },
337 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
338 SVGGraphicsElementTypeId::SVGImageElement,
339 ))) => node.downcast::<SVGImageElement>().unwrap() as &dyn VirtualMethods,
340 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGGraphicsElement(
341 SVGGraphicsElementTypeId::SVGSVGElement,
342 ))) => node.downcast::<SVGSVGElement>().unwrap() as &dyn VirtualMethods,
343 NodeTypeId::Element(ElementTypeId::SVGElement(SVGElementTypeId::SVGElement)) => {
344 node.downcast::<SVGElement>().unwrap() as &dyn VirtualMethods
345 },
346 NodeTypeId::Element(ElementTypeId::Element) => {
347 node.downcast::<Element>().unwrap() as &dyn VirtualMethods
348 },
349 NodeTypeId::Element(_) => node.downcast::<HTMLElement>().unwrap() as &dyn VirtualMethods,
350 NodeTypeId::DocumentFragment(DocumentFragmentTypeId::ShadowRoot) => {
351 node.downcast::<ShadowRoot>().unwrap() as &dyn VirtualMethods
352 },
353 NodeTypeId::DocumentFragment(_) => {
354 node.downcast::<DocumentFragment>().unwrap() as &dyn VirtualMethods
355 },
356 _ => node as &dyn VirtualMethods,
357 }
358}