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/events/ThreadLocalEventNames.h"
32 #include "core/html/HTMLMediaElement.h"
33 #include "core/html/track/InbandTextTrack.h"
34 #include "core/html/track/LoadableTextTrack.h"
35 #include "core/html/track/TextTrack.h"
36 #include "core/html/track/TrackEvent.h"
38 using namespace WebCore;
40 TextTrackList::TextTrackList(HTMLMediaElement* owner)
42 , m_asyncEventQueue(GenericEventQueue::create(this))
44 ScriptWrappable::init(this);
47 TextTrackList::~TextTrackList()
49 m_asyncEventQueue->close();
52 unsigned TextTrackList::length() const
54 return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
57 int TextTrackList::getTrackIndex(TextTrack *textTrack)
59 if (textTrack->trackType() == TextTrack::TrackElement)
60 return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
62 if (textTrack->trackType() == TextTrack::AddTrack)
63 return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
65 if (textTrack->trackType() == TextTrack::InBand)
66 return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
73 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
75 // 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."
78 for (size_t i = 0; i < m_elementTracks.size(); ++i) {
79 if (!m_elementTracks[i]->isRendered())
82 if (m_elementTracks[i] == textTrack)
87 for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
88 if (!m_addTrackTracks[i]->isRendered())
91 if (m_addTrackTracks[i] == textTrack)
96 for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
97 if (!m_inbandTracks[i]->isRendered())
100 if (m_inbandTracks[i] == textTrack)
105 ASSERT_NOT_REACHED();
110 TextTrack* TextTrackList::item(unsigned index)
112 // 4.8.10.12.1 Text track model
113 // The text tracks are sorted as follows:
114 // 1. The text tracks corresponding to track element children of the media element, in tree order.
115 // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
116 // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
117 // resource), in the order defined by the media resource's format specification.
119 if (index < m_elementTracks.size())
120 return m_elementTracks[index].get();
122 index -= m_elementTracks.size();
123 if (index < m_addTrackTracks.size())
124 return m_addTrackTracks[index].get();
126 index -= m_addTrackTracks.size();
127 if (index < m_inbandTracks.size())
128 return m_inbandTracks[index].get();
133 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
135 // 4.8.10.12.5 Text track API
136 // The getTrackById(id) method must return the first TextTrack in the
137 // TextTrackList object whose id IDL attribute would return a value equal
138 // to the value of the id argument.
139 for (unsigned i = 0; i < length(); ++i) {
140 TextTrack* track = item(i);
141 if (track->id() == id)
145 // When no tracks match the given argument, the method must return null.
149 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
151 Vector<RefPtr<TextTrack> >* tracks = 0;
153 if (track->trackType() == TextTrack::TrackElement) {
154 tracks = &m_elementTracks;
155 for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
156 m_addTrackTracks[i]->invalidateTrackIndex();
157 for (size_t i = 0; i < m_inbandTracks.size(); ++i)
158 m_inbandTracks[i]->invalidateTrackIndex();
159 } else if (track->trackType() == TextTrack::AddTrack) {
160 tracks = &m_addTrackTracks;
161 for (size_t i = 0; i < m_inbandTracks.size(); ++i)
162 m_inbandTracks[i]->invalidateTrackIndex();
163 } else if (track->trackType() == TextTrack::InBand)
164 tracks = &m_inbandTracks;
166 ASSERT_NOT_REACHED();
168 size_t index = tracks->find(track);
169 if (index == kNotFound)
172 for (size_t i = index; i < tracks->size(); ++i)
173 tracks->at(index)->invalidateTrackIndex();
176 void TextTrackList::append(PassRefPtr<TextTrack> prpTrack)
178 RefPtr<TextTrack> track = prpTrack;
180 if (track->trackType() == TextTrack::AddTrack)
181 m_addTrackTracks.append(track);
182 else if (track->trackType() == TextTrack::TrackElement) {
183 // Insert tracks added for <track> element in tree order.
184 size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
185 m_elementTracks.insert(index, track);
186 } else if (track->trackType() == TextTrack::InBand) {
187 // Insert tracks added for in-band in the media file order.
188 size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
189 m_inbandTracks.insert(index, track);
191 ASSERT_NOT_REACHED();
193 invalidateTrackIndexesAfterTrack(track.get());
195 ASSERT(!track->trackList());
196 track->setTrackList(this);
198 scheduleAddTrackEvent(track.release());
201 void TextTrackList::remove(TextTrack* track)
203 Vector<RefPtr<TextTrack> >* tracks = 0;
204 RefPtr<InbandTextTrack> inbandTrack;
206 if (track->trackType() == TextTrack::TrackElement) {
207 tracks = &m_elementTracks;
208 } else if (track->trackType() == TextTrack::AddTrack) {
209 tracks = &m_addTrackTracks;
210 } else if (track->trackType() == TextTrack::InBand) {
211 tracks = &m_inbandTracks;
212 inbandTrack = static_cast<InbandTextTrack*>(track);
214 ASSERT_NOT_REACHED();
217 size_t index = tracks->find(track);
218 if (index == kNotFound)
221 invalidateTrackIndexesAfterTrack(track);
223 ASSERT(track->trackList() == this);
224 track->setTrackList(0);
226 tracks->remove(index);
229 inbandTrack->trackRemoved();
231 scheduleRemoveTrackEvent(track);
234 bool TextTrackList::contains(TextTrack* track) const
236 const Vector<RefPtr<TextTrack> >* tracks = 0;
238 if (track->trackType() == TextTrack::TrackElement)
239 tracks = &m_elementTracks;
240 else if (track->trackType() == TextTrack::AddTrack)
241 tracks = &m_addTrackTracks;
242 else if (track->trackType() == TextTrack::InBand)
243 tracks = &m_inbandTracks;
245 ASSERT_NOT_REACHED();
247 return tracks->find(track) != kNotFound;
250 const AtomicString& TextTrackList::interfaceName() const
252 return EventTargetNames::TextTrackList;
255 ExecutionContext* TextTrackList::executionContext() const
258 return m_owner->executionContext();
261 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtr<TextTrack> track)
263 TrackEventInit initializer;
264 initializer.track = track;
265 initializer.bubbles = false;
266 initializer.cancelable = false;
268 m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
271 void TextTrackList::scheduleAddTrackEvent(PassRefPtr<TextTrack> track)
273 // 4.8.10.12.3 Sourcing out-of-band text tracks
274 // 4.8.10.12.4 Text track API
275 // ... then queue a task to fire an event with the name addtrack, that does not
276 // bubble and is not cancelable, and that uses the TrackEvent interface, with
277 // the track attribute initialized to the text track's TextTrack object, at
278 // the media element's textTracks attribute's TextTrackList object.
279 scheduleTrackEvent(EventTypeNames::addtrack, track);
282 void TextTrackList::scheduleChangeEvent()
284 // 4.8.10.12.1 Text track model
285 // Whenever a text track that is in a media element's list of text tracks
286 // has its text track mode change value, the user agent must run the
287 // following steps for the media element:
289 // Fire a simple event named change at the media element's textTracks
290 // attribute's TextTrackList object.
292 EventInit initializer;
293 initializer.bubbles = false;
294 initializer.cancelable = false;
296 m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change, initializer));
299 void TextTrackList::scheduleRemoveTrackEvent(PassRefPtr<TextTrack> track)
301 // 4.8.10.12.3 Sourcing out-of-band text tracks
302 // When a track element's parent element changes and the old parent was a
303 // media element, then the user agent must remove the track element's
304 // corresponding text track from the media element's list of text tracks,
305 // and then queue a task to fire a trusted event with the name removetrack,
306 // that does not bubble and is not cancelable, and that uses the TrackEvent
307 // interface, with the track attribute initialized to the text track's
308 // TextTrack object, at the media element's textTracks attribute's
309 // TextTrackList object.
310 scheduleTrackEvent(EventTypeNames::removetrack, track);
313 Node* TextTrackList::owner() const