Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / track / TextTrackList.cpp
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/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"
37
38 using namespace WebCore;
39
40 TextTrackList::TextTrackList(HTMLMediaElement* owner)
41     : m_owner(owner)
42     , m_asyncEventQueue(GenericEventQueue::create(this))
43 {
44     ScriptWrappable::init(this);
45 }
46
47 TextTrackList::~TextTrackList()
48 {
49     m_asyncEventQueue->close();
50 }
51
52 unsigned TextTrackList::length() const
53 {
54     return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
55 }
56
57 int TextTrackList::getTrackIndex(TextTrack *textTrack)
58 {
59     if (textTrack->trackType() == TextTrack::TrackElement)
60         return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
61
62     if (textTrack->trackType() == TextTrack::AddTrack)
63         return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
64
65     if (textTrack->trackType() == TextTrack::InBand)
66         return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
67
68     ASSERT_NOT_REACHED();
69
70     return -1;
71 }
72
73 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
74 {
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."
76     int trackIndex = 0;
77
78     for (size_t i = 0; i < m_elementTracks.size(); ++i) {
79         if (!m_elementTracks[i]->isRendered())
80             continue;
81
82         if (m_elementTracks[i] == textTrack)
83             return trackIndex;
84         ++trackIndex;
85     }
86
87     for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
88         if (!m_addTrackTracks[i]->isRendered())
89             continue;
90
91         if (m_addTrackTracks[i] == textTrack)
92             return trackIndex;
93         ++trackIndex;
94     }
95
96     for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
97         if (!m_inbandTracks[i]->isRendered())
98             continue;
99
100         if (m_inbandTracks[i] == textTrack)
101             return trackIndex;
102         ++trackIndex;
103     }
104
105     ASSERT_NOT_REACHED();
106
107     return -1;
108 }
109
110 TextTrack* TextTrackList::item(unsigned index)
111 {
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.
118
119     if (index < m_elementTracks.size())
120         return m_elementTracks[index].get();
121
122     index -= m_elementTracks.size();
123     if (index < m_addTrackTracks.size())
124         return m_addTrackTracks[index].get();
125
126     index -= m_addTrackTracks.size();
127     if (index < m_inbandTracks.size())
128         return m_inbandTracks[index].get();
129
130     return 0;
131 }
132
133 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
134 {
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)
142             return track;
143     }
144
145     // When no tracks match the given argument, the method must return null.
146     return 0;
147 }
148
149 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
150 {
151     Vector<RefPtr<TextTrack> >* tracks = 0;
152
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;
165     else
166         ASSERT_NOT_REACHED();
167
168     size_t index = tracks->find(track);
169     if (index == kNotFound)
170         return;
171
172     for (size_t i = index; i < tracks->size(); ++i)
173         tracks->at(index)->invalidateTrackIndex();
174 }
175
176 void TextTrackList::append(PassRefPtr<TextTrack> prpTrack)
177 {
178     RefPtr<TextTrack> track = prpTrack;
179
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);
190     } else
191         ASSERT_NOT_REACHED();
192
193     invalidateTrackIndexesAfterTrack(track.get());
194
195     ASSERT(!track->trackList());
196     track->setTrackList(this);
197
198     scheduleAddTrackEvent(track.release());
199 }
200
201 void TextTrackList::remove(TextTrack* track)
202 {
203     Vector<RefPtr<TextTrack> >* tracks = 0;
204     RefPtr<InbandTextTrack> inbandTrack;
205
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);
213     } else {
214         ASSERT_NOT_REACHED();
215     }
216
217     size_t index = tracks->find(track);
218     if (index == kNotFound)
219         return;
220
221     invalidateTrackIndexesAfterTrack(track);
222
223     ASSERT(track->trackList() == this);
224     track->setTrackList(0);
225
226     tracks->remove(index);
227
228     if (inbandTrack)
229         inbandTrack->trackRemoved();
230
231     scheduleRemoveTrackEvent(track);
232 }
233
234 bool TextTrackList::contains(TextTrack* track) const
235 {
236     const Vector<RefPtr<TextTrack> >* tracks = 0;
237
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;
244     else
245         ASSERT_NOT_REACHED();
246
247     return tracks->find(track) != kNotFound;
248 }
249
250 const AtomicString& TextTrackList::interfaceName() const
251 {
252     return EventTargetNames::TextTrackList;
253 }
254
255 ExecutionContext* TextTrackList::executionContext() const
256 {
257     ASSERT(m_owner);
258     return m_owner->executionContext();
259 }
260
261 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtr<TextTrack> track)
262 {
263     TrackEventInit initializer;
264     initializer.track = track;
265     initializer.bubbles = false;
266     initializer.cancelable = false;
267
268     m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
269 }
270
271 void TextTrackList::scheduleAddTrackEvent(PassRefPtr<TextTrack> track)
272 {
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);
280 }
281
282 void TextTrackList::scheduleChangeEvent()
283 {
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:
288     // ...
289     // Fire a simple event named change at the media element's textTracks
290     // attribute's TextTrackList object.
291
292     EventInit initializer;
293     initializer.bubbles = false;
294     initializer.cancelable = false;
295
296     m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change, initializer));
297 }
298
299 void TextTrackList::scheduleRemoveTrackEvent(PassRefPtr<TextTrack> track)
300 {
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);
311 }
312
313 Node* TextTrackList::owner() const
314 {
315     return m_owner;
316 }