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