Skip to main content

script/dom/webvtt/
texttrackcuelist.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::ops::Deref;
6
7use dom_struct::dom_struct;
8use js::context::{JSContext, NoGC};
9use script_bindings::cell::DomRefCell;
10use script_bindings::reflector::{Reflector, reflect_dom_object};
11
12use crate::dom::bindings::codegen::Bindings::TextTrackCueListBinding::TextTrackCueListMethods;
13use crate::dom::bindings::root::{Dom, DomRoot, MutDom, UnrootedDom};
14use crate::dom::bindings::str::DOMString;
15use crate::dom::texttrack::TextTrack;
16use crate::dom::texttrackcue::TextTrackCue;
17use crate::dom::window::Window;
18
19#[dom_struct]
20pub(crate) struct TextTrackCueList {
21    reflector_: Reflector,
22    text_track: MutDom<TextTrack>,
23    dom_cues: DomRefCell<Vec<Dom<TextTrackCue>>>,
24}
25
26impl TextTrackCueList {
27    pub(crate) fn new_inherited(text_track: &TextTrack) -> TextTrackCueList {
28        TextTrackCueList {
29            reflector_: Reflector::new(),
30            text_track: MutDom::new(text_track),
31            dom_cues: Default::default(),
32        }
33    }
34
35    pub(crate) fn new(
36        cx: &mut JSContext,
37        text_track: &TextTrack,
38        window: &Window,
39    ) -> DomRoot<TextTrackCueList> {
40        reflect_dom_object(
41            cx,
42            Box::new(TextTrackCueList::new_inherited(text_track)),
43            window,
44        )
45    }
46
47    pub(crate) fn item(&self, idx: usize) -> Option<DomRoot<TextTrackCue>> {
48        self.dom_cues
49            .borrow()
50            .get(idx)
51            .map(|t| DomRoot::from_ref(&**t))
52    }
53
54    pub(crate) fn find(&self, cue: &TextTrackCue) -> Option<usize> {
55        self.dom_cues
56            .borrow()
57            .iter()
58            .enumerate()
59            .find(|(_, c)| **c == cue)
60            .map(|(i, _)| i)
61    }
62
63    /// <https://html.spec.whatwg.org/multipage/#text-track-cue-order>
64    pub(crate) fn sort(&self) {
65        // Manually call `Ord::cmp` since `Dom<T>` doesn't implement Ord
66        self.dom_cues.borrow_mut().sort_by(|a, b| a.cmp(b));
67    }
68
69    pub(crate) fn add(&self, cx: &mut JSContext, cue: &TextTrackCue) {
70        // Only add a cue if it does not exist in the list
71        if self.find(cue).is_none() {
72            {
73                let mut dom_cues = self.dom_cues.borrow_mut();
74                dom_cues.push(Dom::from_ref(cue));
75                cue.set_initial_index_in_list(dom_cues.len());
76            }
77            self.sort();
78            let text_track = self.text_track.get();
79            // https://html.spec.whatwg.org/multipage/#dom-media-addtexttrack
80            // > When a text track cue is added to it,
81            // > the text track list of cues has its rules permanently set accordingly.
82            if text_track
83                .rules_for_updating_the_text_track_rendering()
84                .is_none()
85            {
86                text_track.set_rules_for_updating_the_text_track_rendering(
87                    cue.rules_for_updating_the_text_track_rendering(),
88                );
89            }
90            if let Some(track_list) = text_track.track_list() {
91                track_list.notify_media_element_for_added_cue(cx, cue);
92            }
93        }
94    }
95
96    pub(crate) fn refresh_active_cues<'no_gc>(
97        &self,
98        no_gc: &'no_gc NoGC,
99        other: UnrootedDom<'no_gc, TextTrackCueList>,
100    ) {
101        *self.dom_cues.safe_borrow_mut(no_gc) = other
102            .cues(no_gc)
103            .iter()
104            .filter(|cue| cue.is_active())
105            .map(|cue| cue.deref().clone())
106            .collect();
107    }
108
109    pub(crate) fn remove(&self, idx: usize) {
110        self.dom_cues.borrow_mut().remove(idx);
111    }
112
113    pub(crate) fn empty(&self) {
114        self.dom_cues.borrow_mut().clear();
115    }
116
117    pub(crate) fn cues<'no_gc>(
118        &self,
119        no_gc: &'no_gc NoGC,
120    ) -> Vec<UnrootedDom<'no_gc, TextTrackCue>> {
121        self.dom_cues
122            .borrow()
123            .clone()
124            .into_iter()
125            .map(|track| track.as_unrooted(no_gc))
126            .collect()
127    }
128}
129
130impl TextTrackCueListMethods<crate::DomTypeHolder> for TextTrackCueList {
131    /// <https://html.spec.whatwg.org/multipage/#dom-texttrackcuelist-length>
132    fn Length(&self) -> u32 {
133        self.dom_cues.borrow().len() as u32
134    }
135
136    /// <https://html.spec.whatwg.org/multipage/#dom-texttrackcuelist-item>
137    fn IndexedGetter(&self, idx: u32) -> Option<DomRoot<TextTrackCue>> {
138        self.item(idx as usize)
139    }
140
141    /// <https://html.spec.whatwg.org/multipage/#dom-texttrackcuelist-getcuebyid>
142    fn GetCueById(&self, id: DOMString) -> Option<DomRoot<TextTrackCue>> {
143        if id.is_empty() {
144            None
145        } else {
146            self.dom_cues
147                .borrow()
148                .iter()
149                .find(|cue| cue.id() == id)
150                .map(|t| DomRoot::from_ref(&**t))
151        }
152    }
153}