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/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"
37 using namespace blink;
39 TextTrackList::TextTrackList(HTMLMediaElement* owner)
41 , m_asyncEventQueue(GenericEventQueue::create(this))
45 TextTrackList::~TextTrackList()
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();
55 for (unsigned i = 0; i < length(); ++i) {
56 item(i)->setTrackList(0);
61 unsigned TextTrackList::length() const
63 return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
66 int TextTrackList::getTrackIndex(TextTrack *textTrack)
68 if (textTrack->trackType() == TextTrack::TrackElement)
69 return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
71 if (textTrack->trackType() == TextTrack::AddTrack)
72 return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
74 if (textTrack->trackType() == TextTrack::InBand)
75 return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
82 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
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."
87 for (size_t i = 0; i < m_elementTracks.size(); ++i) {
88 if (!m_elementTracks[i]->isRendered())
91 if (m_elementTracks[i] == textTrack)
96 for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
97 if (!m_addTrackTracks[i]->isRendered())
100 if (m_addTrackTracks[i] == textTrack)
105 for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
106 if (!m_inbandTracks[i]->isRendered())
109 if (m_inbandTracks[i] == textTrack)
114 ASSERT_NOT_REACHED();
119 TextTrack* TextTrackList::item(unsigned index)
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.
128 if (index < m_elementTracks.size())
129 return m_elementTracks[index].get();
131 index -= m_elementTracks.size();
132 if (index < m_addTrackTracks.size())
133 return m_addTrackTracks[index].get();
135 index -= m_addTrackTracks.size();
136 if (index < m_inbandTracks.size())
137 return m_inbandTracks[index].get();
142 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
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)
154 // When no tracks match the given argument, the method must return null.
158 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
160 WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
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;
175 ASSERT_NOT_REACHED();
178 size_t index = tracks->find(track);
179 if (index == kNotFound)
182 for (size_t i = index; i < tracks->size(); ++i)
183 tracks->at(index)->invalidateTrackIndex();
186 void TextTrackList::append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)
188 RefPtrWillBeRawPtr<TextTrack> track = prpTrack;
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);
201 ASSERT_NOT_REACHED();
204 invalidateTrackIndexesAfterTrack(track.get());
206 ASSERT(!track->trackList());
207 track->setTrackList(this);
209 scheduleAddTrackEvent(track.release());
212 void TextTrackList::remove(TextTrack* track)
214 WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
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;
223 ASSERT_NOT_REACHED();
226 size_t index = tracks->find(track);
227 if (index == kNotFound)
230 invalidateTrackIndexesAfterTrack(track);
232 ASSERT(track->trackList() == this);
233 track->setTrackList(0);
235 tracks->remove(index);
237 scheduleRemoveTrackEvent(track);
240 void TextTrackList::removeAllInbandTracks()
242 for (unsigned i = 0; i < m_inbandTracks.size(); ++i) {
243 m_inbandTracks[i]->setTrackList(0);
245 m_inbandTracks.clear();
248 bool TextTrackList::contains(TextTrack* track) const
250 const WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
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;
259 ASSERT_NOT_REACHED();
261 return tracks->find(track) != kNotFound;
264 const AtomicString& TextTrackList::interfaceName() const
266 return EventTargetNames::TextTrackList;
269 ExecutionContext* TextTrackList::executionContext() const
271 return m_owner ? m_owner->executionContext() : 0;
275 void TextTrackList::clearOwner()
281 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<TextTrack> track)
283 TrackEventInit initializer;
284 initializer.track = track;
285 initializer.bubbles = false;
286 initializer.cancelable = false;
288 m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
291 void TextTrackList::scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
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);
302 void TextTrackList::scheduleChangeEvent()
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:
309 // Fire a simple event named change at the media element's textTracks
310 // attribute's TextTrackList object.
312 m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change));
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_asyncEventQueue);
338 visitor->trace(m_addTrackTracks);
339 visitor->trace(m_elementTracks);
340 visitor->trace(m_inbandTracks);
341 EventTargetWithInlineData::trace(visitor);