1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8
9use crate::dom::bindings::cell::DomRefCell;
10use crate::dom::bindings::codegen::Bindings::TextTrackBinding::{
11 TextTrackKind, TextTrackMethods, TextTrackMode,
12};
13use crate::dom::bindings::error::{Error, ErrorResult};
14use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
15use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
16use crate::dom::bindings::str::DOMString;
17use crate::dom::eventtarget::EventTarget;
18use crate::dom::texttrackcue::TextTrackCue;
19use crate::dom::texttrackcuelist::TextTrackCueList;
20use crate::dom::texttracklist::TextTrackList;
21use crate::dom::window::Window;
22use crate::script_runtime::CanGc;
23
24#[dom_struct]
25pub(crate) struct TextTrack {
26 eventtarget: EventTarget,
27 kind: TextTrackKind,
28 label: String,
29 language: String,
30 id: String,
31 mode: Cell<TextTrackMode>,
32 cue_list: MutNullableDom<TextTrackCueList>,
33 track_list: DomRefCell<Option<Dom<TextTrackList>>>,
34}
35
36impl TextTrack {
37 pub(crate) fn new_inherited(
38 id: DOMString,
39 kind: TextTrackKind,
40 label: DOMString,
41 language: DOMString,
42 mode: TextTrackMode,
43 track_list: Option<&TextTrackList>,
44 ) -> TextTrack {
45 TextTrack {
46 eventtarget: EventTarget::new_inherited(),
47 kind,
48 label: label.into(),
49 language: language.into(),
50 id: id.into(),
51 mode: Cell::new(mode),
52 cue_list: Default::default(),
53 track_list: DomRefCell::new(track_list.map(Dom::from_ref)),
54 }
55 }
56
57 #[allow(clippy::too_many_arguments)]
58 pub(crate) fn new(
59 window: &Window,
60 id: DOMString,
61 kind: TextTrackKind,
62 label: DOMString,
63 language: DOMString,
64 mode: TextTrackMode,
65 track_list: Option<&TextTrackList>,
66 can_gc: CanGc,
67 ) -> DomRoot<TextTrack> {
68 reflect_dom_object(
69 Box::new(TextTrack::new_inherited(
70 id, kind, label, language, mode, track_list,
71 )),
72 window,
73 can_gc,
74 )
75 }
76
77 pub(crate) fn get_cues(&self) -> DomRoot<TextTrackCueList> {
78 self.cue_list
79 .or_init(|| TextTrackCueList::new(self.global().as_window(), &[], CanGc::note()))
80 }
81
82 pub(crate) fn id(&self) -> &str {
83 &self.id
84 }
85
86 pub(crate) fn add_track_list(&self, track_list: &TextTrackList) {
87 *self.track_list.borrow_mut() = Some(Dom::from_ref(track_list));
88 }
89
90 pub(crate) fn remove_track_list(&self) {
91 *self.track_list.borrow_mut() = None;
92 }
93}
94
95impl TextTrackMethods<crate::DomTypeHolder> for TextTrack {
96 fn Kind(&self) -> TextTrackKind {
98 self.kind
99 }
100
101 fn Label(&self) -> DOMString {
103 DOMString::from(self.label.clone())
104 }
105
106 fn Language(&self) -> DOMString {
108 DOMString::from(self.language.clone())
109 }
110
111 fn Id(&self) -> DOMString {
113 DOMString::from(self.id.clone())
114 }
115
116 fn Mode(&self) -> TextTrackMode {
118 self.mode.get()
119 }
120
121 fn SetMode(&self, value: TextTrackMode) {
123 self.mode.set(value)
124 }
125
126 fn GetCues(&self) -> Option<DomRoot<TextTrackCueList>> {
128 match self.Mode() {
129 TextTrackMode::Disabled => None,
130 _ => Some(self.get_cues()),
131 }
132 }
133
134 fn GetActiveCues(&self) -> Option<DomRoot<TextTrackCueList>> {
136 Some(TextTrackCueList::new(
139 self.global().as_window(),
140 &[],
141 CanGc::note(),
142 ))
143 }
144
145 fn AddCue(&self, cue: &TextTrackCue) -> ErrorResult {
147 if let Some(old_track) = cue.get_track() {
150 if old_track.RemoveCue(cue).is_err() {
154 warn!("Failed to remove cues for the added cue's text track");
155 }
156 }
157 self.get_cues().add(cue);
159 Ok(())
160 }
161
162 fn RemoveCue(&self, cue: &TextTrackCue) -> ErrorResult {
164 let cues = self.get_cues();
166 let index = match cues.find(cue) {
167 Some(i) => Ok(i),
168 None => Err(Error::NotFound),
169 }?;
170 cues.remove(index);
172 Ok(())
173 }
174
175 event_handler!(cuechange, GetOncuechange, SetOncuechange);
177}