script/dom/html/
htmlsourceelement.rs1use dom_struct::dom_struct;
6use html5ever::{LocalName, Prefix, local_name};
7use js::rust::HandleObject;
8use script_bindings::script_runtime::temp_cx;
9use style::attr::AttrValue;
10
11use crate::dom::attr::Attr;
12use crate::dom::bindings::codegen::Bindings::HTMLSourceElementBinding::HTMLSourceElementMethods;
13use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
14use crate::dom::bindings::inheritance::Castable;
15use crate::dom::bindings::root::{Dom, DomRoot, Root};
16use crate::dom::bindings::str::{DOMString, USVString};
17use crate::dom::document::Document;
18use crate::dom::element::AttributeMutation;
19use crate::dom::html::htmlelement::HTMLElement;
20use crate::dom::html::htmlimageelement::HTMLImageElement;
21use crate::dom::html::htmlmediaelement::HTMLMediaElement;
22use crate::dom::html::htmlpictureelement::HTMLPictureElement;
23use crate::dom::node::{BindContext, Node, NodeDamage, UnbindContext};
24use crate::dom::virtualmethods::VirtualMethods;
25use crate::script_runtime::CanGc;
26
27#[dom_struct]
28pub(crate) struct HTMLSourceElement {
29 htmlelement: HTMLElement,
30}
31
32impl HTMLSourceElement {
33 fn new_inherited(
34 local_name: LocalName,
35 prefix: Option<Prefix>,
36 document: &Document,
37 ) -> HTMLSourceElement {
38 HTMLSourceElement {
39 htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
40 }
41 }
42
43 pub(crate) fn new(
44 local_name: LocalName,
45 prefix: Option<Prefix>,
46 document: &Document,
47 proto: Option<HandleObject>,
48 can_gc: CanGc,
49 ) -> DomRoot<HTMLSourceElement> {
50 Node::reflect_node_with_proto(
51 Box::new(HTMLSourceElement::new_inherited(
52 local_name, prefix, document,
53 )),
54 document,
55 proto,
56 can_gc,
57 )
58 }
59
60 fn iterate_next_html_image_element_siblings(
61 next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>,
62 callback: impl Fn(&HTMLImageElement),
63 ) {
64 for next_sibling in next_siblings_iterator {
65 if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() {
66 callback(html_image_element_sibling);
67 }
68 }
69 }
70
71 fn iterate_next_html_image_element_siblings_with_cx(
72 cx: &mut js::context::JSContext,
73 next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>,
74 callback: impl Fn(&mut js::context::JSContext, &HTMLImageElement),
75 ) {
76 for next_sibling in next_siblings_iterator {
77 if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() {
78 callback(cx, html_image_element_sibling);
79 }
80 }
81 }
82}
83
84impl VirtualMethods for HTMLSourceElement {
85 fn super_type(&self) -> Option<&dyn VirtualMethods> {
86 Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
87 }
88
89 #[expect(unsafe_code)]
90 fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation, _can_gc: CanGc) {
91 let mut cx = unsafe { temp_cx() };
93 let cx = &mut cx;
94 self.super_type()
95 .unwrap()
96 .attribute_mutated(attr, mutation, CanGc::from_cx(cx));
97
98 match attr.local_name() {
99 &local_name!("srcset") |
100 &local_name!("sizes") |
101 &local_name!("media") |
102 &local_name!("type") => {
103 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
107 if parent.is::<HTMLPictureElement>() {
108 let next_sibling_iterator = self.upcast::<Node>().following_siblings();
109 HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
110 cx,
111 next_sibling_iterator,
112 |cx, image| image.update_the_image_data(cx),
113 );
114 }
115 }
116 },
117 &local_name!("width") | &local_name!("height") => {
118 if let Some(parent) = self.upcast::<Node>().GetParentElement() {
123 if parent.is::<HTMLPictureElement>() {
124 let next_sibling_iterator = self.upcast::<Node>().following_siblings();
125 HTMLSourceElement::iterate_next_html_image_element_siblings(
126 next_sibling_iterator,
127 |image| image.upcast::<Node>().dirty(NodeDamage::Other),
128 );
129 }
130 }
131 },
132 _ => {},
133 }
134 }
135
136 fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
137 match name {
138 &local_name!("width") | &local_name!("height") => {
139 AttrValue::from_dimension(value.into())
140 },
141 _ => self
142 .super_type()
143 .unwrap()
144 .parse_plain_attribute(name, value),
145 }
146 }
147
148 #[expect(unsafe_code)]
149 fn bind_to_tree(&self, context: &BindContext, _can_gc: CanGc) {
151 let mut cx = unsafe { temp_cx() };
153 let cx = &mut cx;
154 self.super_type()
155 .unwrap()
156 .bind_to_tree(context, CanGc::from_cx(cx));
157
158 let parent = self.upcast::<Node>().GetParentNode().unwrap();
160
161 if parent.is::<HTMLMediaElement>() && std::ptr::eq(&*parent, context.parent) {
164 parent
165 .downcast::<HTMLMediaElement>()
166 .unwrap()
167 .handle_source_child_insertion(self, cx);
168 }
169
170 if parent.is::<HTMLPictureElement>() && std::ptr::eq(&*parent, context.parent) {
173 let next_sibling_iterator = self.upcast::<Node>().following_siblings();
174 HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
175 cx,
176 next_sibling_iterator,
177 |cx, image| image.update_the_image_data(cx),
178 );
179 }
180 }
181
182 #[expect(unsafe_code)]
183 fn unbind_from_tree(&self, context: &UnbindContext, _can_gc: CanGc) {
185 let mut cx = unsafe { temp_cx() };
187 let cx = &mut cx;
188 self.super_type()
189 .unwrap()
190 .unbind_from_tree(context, CanGc::from_cx(cx));
191
192 if context.parent.is::<HTMLPictureElement>() && !self.upcast::<Node>().has_parent() {
195 if let Some(next_sibling) = context.next_sibling {
196 let next_sibling_iterator = next_sibling.inclusively_following_siblings();
197 HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
198 cx,
199 next_sibling_iterator,
200 |cx, image| image.update_the_image_data(cx),
201 );
202 }
203 }
204 }
205}
206
207impl HTMLSourceElementMethods<crate::DomTypeHolder> for HTMLSourceElement {
208 make_url_getter!(Src, "src");
210
211 make_url_setter!(SetSrc, "src");
213
214 make_getter!(Type, "type");
216
217 make_setter!(SetType, "type");
219
220 make_url_getter!(Srcset, "srcset");
222
223 make_url_setter!(SetSrcset, "srcset");
225
226 make_getter!(Sizes, "sizes");
228
229 make_setter!(SetSizes, "sizes");
231
232 make_getter!(Media, "media");
234
235 make_setter!(SetMedia, "media");
237
238 make_dimension_uint_getter!(Width, "width");
240
241 make_dimension_uint_setter!(SetWidth, "width");
243
244 make_dimension_uint_getter!(Height, "height");
246
247 make_dimension_uint_setter!(SetHeight, "height");
249}