| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ |
| |
| use dom_struct::dom_struct; |
| |
| use crate::dom::bindings::cell::DomRefCell; |
| use crate::dom::bindings::codegen::Bindings::VideoTrackListBinding::VideoTrackListMethods; |
| use crate::dom::bindings::inheritance::Castable; |
| use crate::dom::bindings::refcounted::Trusted; |
| use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object}; |
| use crate::dom::bindings::root::{Dom, DomRoot}; |
| use crate::dom::bindings::str::DOMString; |
| use crate::dom::eventtarget::EventTarget; |
| use crate::dom::html::htmlmediaelement::HTMLMediaElement; |
| use crate::dom::videotrack::VideoTrack; |
| use crate::dom::window::Window; |
| use crate::script_runtime::CanGc; |
| |
| #[dom_struct] |
| pub(crate) struct VideoTrackList { |
| eventtarget: EventTarget, |
| tracks: DomRefCell<Vec<Dom<VideoTrack>>>, |
| media_element: Option<Dom<HTMLMediaElement>>, |
| } |
| |
| impl VideoTrackList { |
| pub(crate) fn new_inherited( |
| tracks: &[&VideoTrack], |
| media_element: Option<&HTMLMediaElement>, |
| ) -> VideoTrackList { |
| VideoTrackList { |
| eventtarget: EventTarget::new_inherited(), |
| tracks: DomRefCell::new(tracks.iter().map(|track| Dom::from_ref(&**track)).collect()), |
| media_element: media_element.map(Dom::from_ref), |
| } |
| } |
| |
| pub(crate) fn new( |
| window: &Window, |
| tracks: &[&VideoTrack], |
| media_element: Option<&HTMLMediaElement>, |
| can_gc: CanGc, |
| ) -> DomRoot<VideoTrackList> { |
| reflect_dom_object( |
| Box::new(VideoTrackList::new_inherited(tracks, media_element)), |
| window, |
| can_gc, |
| ) |
| } |
| |
| pub(crate) fn len(&self) -> usize { |
| self.tracks.borrow().len() |
| } |
| |
| pub(crate) fn find(&self, track: &VideoTrack) -> Option<usize> { |
| self.tracks.borrow().iter().position(|t| &**t == track) |
| } |
| |
| pub(crate) fn item(&self, idx: usize) -> Option<DomRoot<VideoTrack>> { |
| self.tracks |
| .borrow() |
| .get(idx) |
| .map(|track| DomRoot::from_ref(&**track)) |
| } |
| |
| pub(crate) fn selected_index(&self) -> Option<usize> { |
| self.tracks |
| .borrow() |
| .iter() |
| .position(|track| track.selected()) |
| } |
| |
| pub(crate) fn set_selected(&self, idx: usize, value: bool) { |
| let track = match self.item(idx) { |
| Some(t) => t, |
| None => return, |
| }; |
| |
| // If the chosen tracks selected status is the same as the new status, return early. |
| if track.selected() == value { |
| return; |
| } |
| |
| if let Some(current) = self.selected_index() { |
| self.tracks.borrow()[current].set_selected(false); |
| } |
| |
| track.set_selected(value); |
| if let Some(media_element) = self.media_element.as_ref() { |
| media_element.set_video_track(idx, value); |
| } |
| |
| let this = Trusted::new(self); |
| self.global() |
| .task_manager() |
| .media_element_task_source() |
| .queue(task!(media_track_change: move || { |
| let this = this.root(); |
| this.upcast::<EventTarget>().fire_event(atom!("change"), CanGc::note()); |
| })); |
| } |
| |
| pub(crate) fn add(&self, track: &VideoTrack) { |
| self.tracks.borrow_mut().push(Dom::from_ref(track)); |
| if track.selected() { |
| if let Some(idx) = self.selected_index() { |
| self.set_selected(idx, false); |
| } |
| } |
| track.add_track_list(self); |
| } |
| |
| pub(crate) fn clear(&self) { |
| self.tracks |
| .borrow() |
| .iter() |
| .for_each(|t| t.remove_track_list()); |
| self.tracks.borrow_mut().clear(); |
| } |
| } |
| |
| impl VideoTrackListMethods<crate::DomTypeHolder> for VideoTrackList { |
| // https://html.spec.whatwg.org/multipage/#dom-videotracklist-length |
| fn Length(&self) -> u32 { |
| self.len() as u32 |
| } |
| |
| // https://html.spec.whatwg.org/multipage/#dom-tracklist-item |
| fn IndexedGetter(&self, idx: u32) -> Option<DomRoot<VideoTrack>> { |
| self.item(idx as usize) |
| } |
| |
| // https://html.spec.whatwg.org/multipage/#dom-videotracklist-gettrackbyid |
| fn GetTrackById(&self, id: DOMString) -> Option<DomRoot<VideoTrack>> { |
| self.tracks |
| .borrow() |
| .iter() |
| .find(|track| track.id() == id) |
| .map(|track| DomRoot::from_ref(&**track)) |
| } |
| |
| // https://html.spec.whatwg.org/multipage/#dom-videotrack-selected |
| fn SelectedIndex(&self) -> i32 { |
| if let Some(idx) = self.selected_index() { |
| return idx as i32; |
| } |
| -1 |
| } |
| |
| // https://html.spec.whatwg.org/multipage/#handler-tracklist-onchange |
| event_handler!(change, GetOnchange, SetOnchange); |
| |
| // https://html.spec.whatwg.org/multipage/#handler-tracklist-onaddtrack |
| event_handler!(addtrack, GetOnaddtrack, SetOnaddtrack); |
| |
| // https://html.spec.whatwg.org/multipage/#handler-tracklist-onremovetrack |
| event_handler!(removetrack, GetOnremovetrack, SetOnremovetrack); |
| } |