• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011, 2012 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "core/html/track/TextTrackList.h"
28 
29 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
30 #include "core/events/GenericEventQueue.h"
31 #include "core/html/HTMLMediaElement.h"
32 #include "core/html/track/InbandTextTrack.h"
33 #include "core/html/track/LoadableTextTrack.h"
34 #include "core/html/track/TextTrack.h"
35 #include "core/html/track/TrackEvent.h"
36 
37 using namespace blink;
38 
TextTrackList(HTMLMediaElement * owner)39 TextTrackList::TextTrackList(HTMLMediaElement* owner)
40     : m_owner(owner)
41     , m_asyncEventQueue(GenericEventQueue::create(this))
42 {
43 }
44 
~TextTrackList()45 TextTrackList::~TextTrackList()
46 {
47 #if !ENABLE(OILPAN)
48     ASSERT(!m_owner);
49 
50     // TextTrackList and m_asyncEventQueue always become unreachable
51     // together. So TextTrackList and m_asyncEventQueue are destructed in the
52     // same GC. We don't need to close it explicitly in Oilpan.
53     m_asyncEventQueue->close();
54 
55     for (unsigned i = 0; i < length(); ++i) {
56         item(i)->setTrackList(0);
57     }
58 #endif
59 }
60 
length() const61 unsigned TextTrackList::length() const
62 {
63     return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
64 }
65 
getTrackIndex(TextTrack * textTrack)66 int TextTrackList::getTrackIndex(TextTrack *textTrack)
67 {
68     if (textTrack->trackType() == TextTrack::TrackElement)
69         return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
70 
71     if (textTrack->trackType() == TextTrack::AddTrack)
72         return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
73 
74     if (textTrack->trackType() == TextTrack::InBand)
75         return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
76 
77     ASSERT_NOT_REACHED();
78 
79     return -1;
80 }
81 
getTrackIndexRelativeToRenderedTracks(TextTrack * textTrack)82 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
83 {
84     // Calculate the "Let n be the number of text tracks whose text track mode is showing and that are in the media element's list of text tracks before track."
85     int trackIndex = 0;
86 
87     for (size_t i = 0; i < m_elementTracks.size(); ++i) {
88         if (!m_elementTracks[i]->isRendered())
89             continue;
90 
91         if (m_elementTracks[i] == textTrack)
92             return trackIndex;
93         ++trackIndex;
94     }
95 
96     for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
97         if (!m_addTrackTracks[i]->isRendered())
98             continue;
99 
100         if (m_addTrackTracks[i] == textTrack)
101             return trackIndex;
102         ++trackIndex;
103     }
104 
105     for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
106         if (!m_inbandTracks[i]->isRendered())
107             continue;
108 
109         if (m_inbandTracks[i] == textTrack)
110             return trackIndex;
111         ++trackIndex;
112     }
113 
114     ASSERT_NOT_REACHED();
115 
116     return -1;
117 }
118 
item(unsigned index)119 TextTrack* TextTrackList::item(unsigned index)
120 {
121     // 4.8.10.12.1 Text track model
122     // The text tracks are sorted as follows:
123     // 1. The text tracks corresponding to track element children of the media element, in tree order.
124     // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
125     // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
126     // resource), in the order defined by the media resource's format specification.
127 
128     if (index < m_elementTracks.size())
129         return m_elementTracks[index].get();
130 
131     index -= m_elementTracks.size();
132     if (index < m_addTrackTracks.size())
133         return m_addTrackTracks[index].get();
134 
135     index -= m_addTrackTracks.size();
136     if (index < m_inbandTracks.size())
137         return m_inbandTracks[index].get();
138 
139     return 0;
140 }
141 
getTrackById(const AtomicString & id)142 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
143 {
144     // 4.8.10.12.5 Text track API
145     // The getTrackById(id) method must return the first TextTrack in the
146     // TextTrackList object whose id IDL attribute would return a value equal
147     // to the value of the id argument.
148     for (unsigned i = 0; i < length(); ++i) {
149         TextTrack* track = item(i);
150         if (track->id() == id)
151             return track;
152     }
153 
154     // When no tracks match the given argument, the method must return null.
155     return 0;
156 }
157 
invalidateTrackIndexesAfterTrack(TextTrack * track)158 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
159 {
160     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
161 
162     if (track->trackType() == TextTrack::TrackElement) {
163         tracks = &m_elementTracks;
164         for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
165             m_addTrackTracks[i]->invalidateTrackIndex();
166         for (size_t i = 0; i < m_inbandTracks.size(); ++i)
167             m_inbandTracks[i]->invalidateTrackIndex();
168     } else if (track->trackType() == TextTrack::AddTrack) {
169         tracks = &m_addTrackTracks;
170         for (size_t i = 0; i < m_inbandTracks.size(); ++i)
171             m_inbandTracks[i]->invalidateTrackIndex();
172     } else if (track->trackType() == TextTrack::InBand) {
173         tracks = &m_inbandTracks;
174     } else {
175         ASSERT_NOT_REACHED();
176     }
177 
178     size_t index = tracks->find(track);
179     if (index == kNotFound)
180         return;
181 
182     for (size_t i = index; i < tracks->size(); ++i)
183         tracks->at(index)->invalidateTrackIndex();
184 }
185 
append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)186 void TextTrackList::append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)
187 {
188     RefPtrWillBeRawPtr<TextTrack> track = prpTrack;
189 
190     if (track->trackType() == TextTrack::AddTrack) {
191         m_addTrackTracks.append(track);
192     } else if (track->trackType() == TextTrack::TrackElement) {
193         // Insert tracks added for <track> element in tree order.
194         size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
195         m_elementTracks.insert(index, track);
196     } else if (track->trackType() == TextTrack::InBand) {
197         // Insert tracks added for in-band in the media file order.
198         size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
199         m_inbandTracks.insert(index, track);
200     } else {
201         ASSERT_NOT_REACHED();
202     }
203 
204     invalidateTrackIndexesAfterTrack(track.get());
205 
206     ASSERT(!track->trackList());
207     track->setTrackList(this);
208 
209     scheduleAddTrackEvent(track.release());
210 }
211 
remove(TextTrack * track)212 void TextTrackList::remove(TextTrack* track)
213 {
214     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
215 
216     if (track->trackType() == TextTrack::TrackElement) {
217         tracks = &m_elementTracks;
218     } else if (track->trackType() == TextTrack::AddTrack) {
219         tracks = &m_addTrackTracks;
220     } else if (track->trackType() == TextTrack::InBand) {
221         tracks = &m_inbandTracks;
222     } else {
223         ASSERT_NOT_REACHED();
224     }
225 
226     size_t index = tracks->find(track);
227     if (index == kNotFound)
228         return;
229 
230     invalidateTrackIndexesAfterTrack(track);
231 
232     ASSERT(track->trackList() == this);
233     track->setTrackList(0);
234 
235     tracks->remove(index);
236 
237     scheduleRemoveTrackEvent(track);
238 }
239 
removeAllInbandTracks()240 void TextTrackList::removeAllInbandTracks()
241 {
242     for (unsigned i = 0; i < m_inbandTracks.size(); ++i) {
243         m_inbandTracks[i]->setTrackList(0);
244     }
245     m_inbandTracks.clear();
246 }
247 
contains(TextTrack * track) const248 bool TextTrackList::contains(TextTrack* track) const
249 {
250     const WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
251 
252     if (track->trackType() == TextTrack::TrackElement)
253         tracks = &m_elementTracks;
254     else if (track->trackType() == TextTrack::AddTrack)
255         tracks = &m_addTrackTracks;
256     else if (track->trackType() == TextTrack::InBand)
257         tracks = &m_inbandTracks;
258     else
259         ASSERT_NOT_REACHED();
260 
261     return tracks->find(track) != kNotFound;
262 }
263 
interfaceName() const264 const AtomicString& TextTrackList::interfaceName() const
265 {
266     return EventTargetNames::TextTrackList;
267 }
268 
executionContext() const269 ExecutionContext* TextTrackList::executionContext() const
270 {
271     return m_owner ? m_owner->executionContext() : 0;
272 }
273 
274 #if !ENABLE(OILPAN)
clearOwner()275 void TextTrackList::clearOwner()
276 {
277     m_owner = nullptr;
278 }
279 #endif
280 
scheduleTrackEvent(const AtomicString & eventName,PassRefPtrWillBeRawPtr<TextTrack> track)281 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<TextTrack> track)
282 {
283     TrackEventInit initializer;
284     initializer.track = track;
285     initializer.bubbles = false;
286     initializer.cancelable = false;
287 
288     m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
289 }
290 
scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)291 void TextTrackList::scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
292 {
293     // 4.8.10.12.3 Sourcing out-of-band text tracks
294     // 4.8.10.12.4 Text track API
295     // ... then queue a task to fire an event with the name addtrack, that does not
296     // bubble and is not cancelable, and that uses the TrackEvent interface, with
297     // the track attribute initialized to the text track's TextTrack object, at
298     // the media element's textTracks attribute's TextTrackList object.
299     scheduleTrackEvent(EventTypeNames::addtrack, track);
300 }
301 
scheduleChangeEvent()302 void TextTrackList::scheduleChangeEvent()
303 {
304     // 4.8.10.12.1 Text track model
305     // Whenever a text track that is in a media element's list of text tracks
306     // has its text track mode change value, the user agent must run the
307     // following steps for the media element:
308     // ...
309     // Fire a simple event named change at the media element's textTracks
310     // attribute's TextTrackList object.
311 
312     m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change));
313 }
314 
scheduleRemoveTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)315 void TextTrackList::scheduleRemoveTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
316 {
317     // 4.8.10.12.3 Sourcing out-of-band text tracks
318     // When a track element's parent element changes and the old parent was a
319     // media element, then the user agent must remove the track element's
320     // corresponding text track from the media element's list of text tracks,
321     // and then queue a task to fire a trusted event with the name removetrack,
322     // that does not bubble and is not cancelable, and that uses the TrackEvent
323     // interface, with the track attribute initialized to the text track's
324     // TextTrack object, at the media element's textTracks attribute's
325     // TextTrackList object.
326     scheduleTrackEvent(EventTypeNames::removetrack, track);
327 }
328 
owner() const329 HTMLMediaElement* TextTrackList::owner() const
330 {
331     return m_owner;
332 }
333 
trace(Visitor * visitor)334 void TextTrackList::trace(Visitor* visitor)
335 {
336     visitor->trace(m_owner);
337     visitor->trace(m_asyncEventQueue);
338     visitor->trace(m_addTrackTracks);
339     visitor->trace(m_elementTracks);
340     visitor->trace(m_inbandTracks);
341     EventTargetWithInlineData::trace(visitor);
342 }
343