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