use dom_struct::dom_struct;
use html5ever::{LocalName, Prefix, local_name};
use js::context::JSContext;
use js::rust::HandleObject;
use style::attr::AttrValue;
use crate::dom::attr::Attr;
use crate::dom::bindings::codegen::Bindings::HTMLSourceElementBinding::HTMLSourceElementMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::{Dom, DomRoot, Root};
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::document::Document;
use crate::dom::element::AttributeMutation;
use crate::dom::html::htmlelement::HTMLElement;
use crate::dom::html::htmlimageelement::HTMLImageElement;
use crate::dom::html::htmlmediaelement::HTMLMediaElement;
use crate::dom::html::htmlpictureelement::HTMLPictureElement;
use crate::dom::node::{BindContext, Node, NodeDamage, UnbindContext};
use crate::dom::virtualmethods::VirtualMethods;
#[dom_struct]
pub(crate) struct HTMLSourceElement {
htmlelement: HTMLElement,
}
impl HTMLSourceElement {
fn new_inherited(
local_name: LocalName,
prefix: Option<Prefix>,
document: &Document,
) -> HTMLSourceElement {
HTMLSourceElement {
htmlelement: HTMLElement::new_inherited(local_name, prefix, document),
}
}
pub(crate) fn new(
cx: &mut js::context::JSContext,
local_name: LocalName,
prefix: Option<Prefix>,
document: &Document,
proto: Option<HandleObject>,
) -> DomRoot<HTMLSourceElement> {
Node::reflect_node_with_proto(
cx,
Box::new(HTMLSourceElement::new_inherited(
local_name, prefix, document,
)),
document,
proto,
)
}
fn iterate_next_html_image_element_siblings(
next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>,
callback: impl Fn(&HTMLImageElement),
) {
for next_sibling in next_siblings_iterator {
if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() {
callback(html_image_element_sibling);
}
}
}
fn iterate_next_html_image_element_siblings_with_cx(
cx: &mut JSContext,
next_siblings_iterator: impl Iterator<Item = Root<Dom<Node>>>,
callback: impl Fn(&mut JSContext, &HTMLImageElement),
) {
for next_sibling in next_siblings_iterator {
if let Some(html_image_element_sibling) = next_sibling.downcast::<HTMLImageElement>() {
callback(cx, html_image_element_sibling);
}
}
}
}
impl VirtualMethods for HTMLSourceElement {
fn super_type(&self) -> Option<&dyn VirtualMethods> {
Some(self.upcast::<HTMLElement>() as &dyn VirtualMethods)
}
fn attribute_mutated(
&self,
cx: &mut js::context::JSContext,
attr: &Attr,
mutation: AttributeMutation,
) {
self.super_type()
.unwrap()
.attribute_mutated(cx, attr, mutation);
match attr.local_name() {
&local_name!("srcset") |
&local_name!("sizes") |
&local_name!("media") |
&local_name!("type") => {
if let Some(parent) = self.upcast::<Node>().GetParentElement() {
if parent.is::<HTMLPictureElement>() {
let next_sibling_iterator = self.upcast::<Node>().following_siblings();
HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
cx,
next_sibling_iterator,
|cx, image| image.update_the_image_data(cx),
);
}
}
},
&local_name!("width") | &local_name!("height") => {
if let Some(parent) = self.upcast::<Node>().GetParentElement() {
if parent.is::<HTMLPictureElement>() {
let next_sibling_iterator = self.upcast::<Node>().following_siblings();
HTMLSourceElement::iterate_next_html_image_element_siblings(
next_sibling_iterator,
|image| image.upcast::<Node>().dirty(NodeDamage::Other),
);
}
}
},
_ => {},
}
}
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
match name {
&local_name!("width") | &local_name!("height") => {
AttrValue::from_dimension(value.into())
},
_ => self
.super_type()
.unwrap()
.parse_plain_attribute(name, value),
}
}
fn bind_to_tree(&self, cx: &mut JSContext, context: &BindContext) {
self.super_type().unwrap().bind_to_tree(cx, context);
let parent = self.upcast::<Node>().GetParentNode().unwrap();
if parent.is::<HTMLMediaElement>() && std::ptr::eq(&*parent, context.parent) {
parent
.downcast::<HTMLMediaElement>()
.unwrap()
.handle_source_child_insertion(self, cx);
}
if parent.is::<HTMLPictureElement>() && std::ptr::eq(&*parent, context.parent) {
let next_sibling_iterator = self.upcast::<Node>().following_siblings();
HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
cx,
next_sibling_iterator,
|cx, image| image.update_the_image_data(cx),
);
}
}
fn unbind_from_tree(&self, cx: &mut js::context::JSContext, context: &UnbindContext) {
self.super_type().unwrap().unbind_from_tree(cx, context);
if context.parent.is::<HTMLPictureElement>() && !self.upcast::<Node>().has_parent() {
if let Some(next_sibling) = context.next_sibling {
let next_sibling_iterator = next_sibling.inclusively_following_siblings();
HTMLSourceElement::iterate_next_html_image_element_siblings_with_cx(
cx,
next_sibling_iterator,
|cx, image| image.update_the_image_data(cx),
);
}
}
}
}
impl HTMLSourceElementMethods<crate::DomTypeHolder> for HTMLSourceElement {
make_url_getter!(Src, "src");
make_url_setter!(SetSrc, "src");
make_getter!(Type, "type");
make_setter!(SetType, "type");
make_url_getter!(Srcset, "srcset");
make_url_setter!(SetSrcset, "srcset");
make_getter!(Sizes, "sizes");
make_setter!(SetSizes, "sizes");
make_getter!(Media, "media");
make_setter!(SetMedia, "media");
make_dimension_uint_getter!(Width, "width");
make_dimension_uint_setter!(SetWidth, "width");
make_dimension_uint_getter!(Height, "height");
make_dimension_uint_setter!(SetHeight, "height");
}