script/dom/webvtt/
texttrack.rs1use 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 #[expect(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.or_init(|| {
79 TextTrackCueList::new(self.global().as_window(), &[], CanGc::deprecated_note())
80 })
81 }
82
83 pub(crate) fn id(&self) -> &str {
84 &self.id
85 }
86
87 pub(crate) fn add_track_list(&self, track_list: &TextTrackList) {
88 *self.track_list.borrow_mut() = Some(Dom::from_ref(track_list));
89 }
90
91 pub(crate) fn remove_track_list(&self) {
92 *self.track_list.borrow_mut() = None;
93 }
94}
95
96impl TextTrackMethods<crate::DomTypeHolder> for TextTrack {
97 fn Kind(&self) -> TextTrackKind {
99 self.kind
100 }
101
102 fn Label(&self) -> DOMString {
104 DOMString::from(self.label.clone())
105 }
106
107 fn Language(&self) -> DOMString {
109 DOMString::from(self.language.clone())
110 }
111
112 fn Id(&self) -> DOMString {
114 DOMString::from(self.id.clone())
115 }
116
117 fn Mode(&self) -> TextTrackMode {
119 self.mode.get()
120 }
121
122 fn SetMode(&self, value: TextTrackMode) {
124 self.mode.set(value)
125 }
126
127 fn GetCues(&self) -> Option<DomRoot<TextTrackCueList>> {
129 match self.Mode() {
130 TextTrackMode::Disabled => None,
131 _ => Some(self.get_cues()),
132 }
133 }
134
135 fn GetActiveCues(&self) -> Option<DomRoot<TextTrackCueList>> {
137 Some(TextTrackCueList::new(
140 self.global().as_window(),
141 &[],
142 CanGc::deprecated_note(),
143 ))
144 }
145
146 fn AddCue(&self, cue: &TextTrackCue) -> ErrorResult {
148 if let Some(old_track) = cue.get_track() {
151 if old_track.RemoveCue(cue).is_err() {
155 warn!("Failed to remove cues for the added cue's text track");
156 }
157 }
158 self.get_cues().add(cue);
160 Ok(())
161 }
162
163 fn RemoveCue(&self, cue: &TextTrackCue) -> ErrorResult {
165 let cues = self.get_cues();
167 let index = match cues.find(cue) {
168 Some(i) => Ok(i),
169 None => Err(Error::NotFound(None)),
170 }?;
171 cues.remove(index);
173 Ok(())
174 }
175
176 event_handler!(cuechange, GetOncuechange, SetOncuechange);
178}