2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/html/track/TextTrackList.h"
29 #include "bindings/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"
37 using namespace WebCore;
39 TextTrackList::TextTrackList(HTMLMediaElement* owner)
41 , m_asyncEventQueue(GenericEventQueue::create(this))
43 ScriptWrappable::init(this);
46 TextTrackList::~TextTrackList()
51 m_asyncEventQueue->close();
53 for (unsigned i = 0; i < length(); ++i) {
54 item(i)->setTrackList(0);
59 unsigned TextTrackList::length() const
61 return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
64 int TextTrackList::getTrackIndex(TextTrack *textTrack)
66 if (textTrack->trackType() == TextTrack::TrackElement)
67 return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
69 if (textTrack->trackType() == TextTrack::AddTrack)
70 return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
72 if (textTrack->trackType() == TextTrack::InBand)
73 return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
80 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
82 // 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 for (size_t i = 0; i < m_elementTracks.size(); ++i) {
86 if (!m_elementTracks[i]->isRendered())
89 if (m_elementTracks[i] == textTrack)
94 for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
95 if (!m_addTrackTracks[i]->isRendered())
98 if (m_addTrackTracks[i] == textTrack)
103 for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
104 if (!m_inbandTracks[i]->isRendered())
107 if (m_inbandTracks[i] == textTrack)
112 ASSERT_NOT_REACHED();
117 TextTrack* TextTrackList::item(unsigned index)
119 // 4.8.10.12.1 Text track model
120 // The text tracks are sorted as follows:
121 // 1. The text tracks corresponding to track element children of the media element, in tree order.
122 // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
123 // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
124 // resource), in the order defined by the media resource's format specification.
126 if (index < m_elementTracks.size())
127 return m_elementTracks[index].get();
129 index -= m_elementTracks.size();
130 if (index < m_addTrackTracks.size())
131 return m_addTrackTracks[index].get();
133 index -= m_addTrackTracks.size();
134 if (index < m_inbandTracks.size())
135 return m_inbandTracks[index].get();
140 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
142 // 4.8.10.12.5 Text track API
143 // The getTrackById(id) method must return the first TextTrack in the
144 // TextTrackList object whose id IDL attribute would return a value equal
145 // to the value of the id argument.
146 for (unsigned i = 0; i < length(); ++i) {
147 TextTrack* track = item(i);
148 if (track->id() == id)
152 // When no tracks match the given argument, the method must return null.
156 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
158 WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
160 if (track->trackType() == TextTrack::TrackElement) {
161 tracks = &m_elementTracks;
162 for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
163 m_addTrackTracks[i]->invalidateTrackIndex();
164 for (size_t i = 0; i < m_inbandTracks.size(); ++i)
165 m_inbandTracks[i]->invalidateTrackIndex();
166 } else if (track->trackType() == TextTrack::AddTrack) {
167 tracks = &m_addTrackTracks;
168 for (size_t i = 0; i < m_inbandTracks.size(); ++i)
169 m_inbandTracks[i]->invalidateTrackIndex();
170 } else if (track->trackType() == TextTrack::InBand)
171 tracks = &m_inbandTracks;
173 ASSERT_NOT_REACHED();
175 size_t index = tracks->find(track);
176 if (index == kNotFound)
179 for (size_t i = index; i < tracks->size(); ++i)
180 tracks->at(index)->invalidateTrackIndex();
183 void TextTrackList::append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)
185 RefPtrWillBeRawPtr<TextTrack> track = prpTrack;
187 if (track->trackType() == TextTrack::AddTrack)
188 m_addTrackTracks.append(track);
189 else if (track->trackType() == TextTrack::TrackElement) {
190 // Insert tracks added for <track> element in tree order.
191 size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
192 m_elementTracks.insert(index, track);
193 } else if (track->trackType() == TextTrack::InBand) {
194 // Insert tracks added for in-band in the media file order.
195 size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
196 m_inbandTracks.insert(index, track);
198 ASSERT_NOT_REACHED();
200 invalidateTrackIndexesAfterTrack(track.get());
202 ASSERT(!track->trackList());
203 track->setTrackList(this);
205 scheduleAddTrackEvent(track.release());
208 void TextTrackList::remove(TextTrack* track)
210 WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
212 if (track->trackType() == TextTrack::TrackElement) {
213 tracks = &m_elementTracks;
214 } else if (track->trackType() == TextTrack::AddTrack) {
215 tracks = &m_addTrackTracks;
216 } else if (track->trackType() == TextTrack::InBand) {
217 tracks = &m_inbandTracks;
219 ASSERT_NOT_REACHED();
222 size_t index = tracks->find(track);
223 if (index == kNotFound)
226 invalidateTrackIndexesAfterTrack(track);
228 ASSERT(track->trackList() == this);
229 track->setTrackList(0);
231 tracks->remove(index);
233 scheduleRemoveTrackEvent(track);
236 void TextTrackList::removeAllInbandTracks()
238 for (unsigned i = 0; i < m_inbandTracks.size(); ++i) {
239 m_inbandTracks[i]->setTrackList(0);
241 m_inbandTracks.clear();
244 bool TextTrackList::contains(TextTrack* track) const
246 const WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
248 if (track->trackType() == TextTrack::TrackElement)
249 tracks = &m_elementTracks;
250 else if (track->trackType() == TextTrack::AddTrack)
251 tracks = &m_addTrackTracks;
252 else if (track->trackType() == TextTrack::InBand)
253 tracks = &m_inbandTracks;
255 ASSERT_NOT_REACHED();
257 return tracks->find(track) != kNotFound;
260 const AtomicString& TextTrackList::interfaceName() const
262 return EventTargetNames::TextTrackList;
265 ExecutionContext* TextTrackList::executionContext() const
267 return m_owner ? m_owner->executionContext() : 0;
271 void TextTrackList::clearOwner()
277 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<TextTrack> track)
279 TrackEventInit initializer;
280 initializer.track = track;
281 initializer.bubbles = false;
282 initializer.cancelable = false;
284 m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
287 void TextTrackList::scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
289 // 4.8.10.12.3 Sourcing out-of-band text tracks
290 // 4.8.10.12.4 Text track API
291 // ... then queue a task to fire an event with the name addtrack, that does not
292 // bubble and is not cancelable, and that uses the TrackEvent interface, with
293 // the track attribute initialized to the text track's TextTrack object, at
294 // the media element's textTracks attribute's TextTrackList object.
295 scheduleTrackEvent(EventTypeNames::addtrack, track);
298 void TextTrackList::scheduleChangeEvent()
300 // 4.8.10.12.1 Text track model
301 // Whenever a text track that is in a media element's list of text tracks
302 // has its text track mode change value, the user agent must run the
303 // following steps for the media element:
305 // Fire a simple event named change at the media element's textTracks
306 // attribute's TextTrackList object.
308 EventInit initializer;
309 initializer.bubbles = false;
310 initializer.cancelable = false;
312 m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change, initializer));
315 void TextTrackList::scheduleRemoveTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
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);
329 HTMLMediaElement* TextTrackList::owner() const
334 void TextTrackList::trace(Visitor* visitor)
336 visitor->trace(m_owner);
337 visitor->trace(m_addTrackTracks);
338 visitor->trace(m_elementTracks);
339 visitor->trace(m_inbandTracks);