Upstream version 7.36.149.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/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 WebCore;
38
39 TextTrackList::TextTrackList(HTMLMediaElement* owner)
40     : m_owner(owner)
41     , m_asyncEventQueue(GenericEventQueue::create(this))
42 {
43     ScriptWrappable::init(this);
44 }
45
46 TextTrackList::~TextTrackList()
47 {
48 #if !ENABLE(OILPAN)
49     ASSERT(!m_owner);
50 #endif
51     m_asyncEventQueue->close();
52 #if !ENABLE(OILPAN)
53     for (unsigned i = 0; i < length(); ++i) {
54         item(i)->setTrackList(0);
55     }
56 #endif
57 }
58
59 unsigned TextTrackList::length() const
60 {
61     return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
62 }
63
64 int TextTrackList::getTrackIndex(TextTrack *textTrack)
65 {
66     if (textTrack->trackType() == TextTrack::TrackElement)
67         return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
68
69     if (textTrack->trackType() == TextTrack::AddTrack)
70         return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
71
72     if (textTrack->trackType() == TextTrack::InBand)
73         return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
74
75     ASSERT_NOT_REACHED();
76
77     return -1;
78 }
79
80 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
81 {
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."
83     int trackIndex = 0;
84
85     for (size_t i = 0; i < m_elementTracks.size(); ++i) {
86         if (!m_elementTracks[i]->isRendered())
87             continue;
88
89         if (m_elementTracks[i] == textTrack)
90             return trackIndex;
91         ++trackIndex;
92     }
93
94     for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
95         if (!m_addTrackTracks[i]->isRendered())
96             continue;
97
98         if (m_addTrackTracks[i] == textTrack)
99             return trackIndex;
100         ++trackIndex;
101     }
102
103     for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
104         if (!m_inbandTracks[i]->isRendered())
105             continue;
106
107         if (m_inbandTracks[i] == textTrack)
108             return trackIndex;
109         ++trackIndex;
110     }
111
112     ASSERT_NOT_REACHED();
113
114     return -1;
115 }
116
117 TextTrack* TextTrackList::item(unsigned index)
118 {
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.
125
126     if (index < m_elementTracks.size())
127         return m_elementTracks[index].get();
128
129     index -= m_elementTracks.size();
130     if (index < m_addTrackTracks.size())
131         return m_addTrackTracks[index].get();
132
133     index -= m_addTrackTracks.size();
134     if (index < m_inbandTracks.size())
135         return m_inbandTracks[index].get();
136
137     return 0;
138 }
139
140 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
141 {
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)
149             return track;
150     }
151
152     // When no tracks match the given argument, the method must return null.
153     return 0;
154 }
155
156 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
157 {
158     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
159
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;
172     else
173         ASSERT_NOT_REACHED();
174
175     size_t index = tracks->find(track);
176     if (index == kNotFound)
177         return;
178
179     for (size_t i = index; i < tracks->size(); ++i)
180         tracks->at(index)->invalidateTrackIndex();
181 }
182
183 void TextTrackList::append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)
184 {
185     RefPtrWillBeRawPtr<TextTrack> track = prpTrack;
186
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);
197     } else
198         ASSERT_NOT_REACHED();
199
200     invalidateTrackIndexesAfterTrack(track.get());
201
202     ASSERT(!track->trackList());
203     track->setTrackList(this);
204
205     scheduleAddTrackEvent(track.release());
206 }
207
208 void TextTrackList::remove(TextTrack* track)
209 {
210     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
211
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;
218     } else {
219         ASSERT_NOT_REACHED();
220     }
221
222     size_t index = tracks->find(track);
223     if (index == kNotFound)
224         return;
225
226     invalidateTrackIndexesAfterTrack(track);
227
228     ASSERT(track->trackList() == this);
229     track->setTrackList(0);
230
231     tracks->remove(index);
232
233     scheduleRemoveTrackEvent(track);
234 }
235
236 void TextTrackList::removeAllInbandTracks()
237 {
238     for (unsigned i = 0; i < m_inbandTracks.size(); ++i) {
239         m_inbandTracks[i]->setTrackList(0);
240     }
241     m_inbandTracks.clear();
242 }
243
244 bool TextTrackList::contains(TextTrack* track) const
245 {
246     const WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
247
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;
254     else
255         ASSERT_NOT_REACHED();
256
257     return tracks->find(track) != kNotFound;
258 }
259
260 const AtomicString& TextTrackList::interfaceName() const
261 {
262     return EventTargetNames::TextTrackList;
263 }
264
265 ExecutionContext* TextTrackList::executionContext() const
266 {
267     return m_owner ? m_owner->executionContext() : 0;
268 }
269
270 #if !ENABLE(OILPAN)
271 void TextTrackList::clearOwner()
272 {
273     m_owner = nullptr;
274 }
275 #endif
276
277 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<TextTrack> track)
278 {
279     TrackEventInit initializer;
280     initializer.track = track;
281     initializer.bubbles = false;
282     initializer.cancelable = false;
283
284     m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
285 }
286
287 void TextTrackList::scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
288 {
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);
296 }
297
298 void TextTrackList::scheduleChangeEvent()
299 {
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:
304     // ...
305     // Fire a simple event named change at the media element's textTracks
306     // attribute's TextTrackList object.
307
308     EventInit initializer;
309     initializer.bubbles = false;
310     initializer.cancelable = false;
311
312     m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change, initializer));
313 }
314
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
329 HTMLMediaElement* TextTrackList::owner() const
330 {
331     return m_owner;
332 }
333
334 void TextTrackList::trace(Visitor* visitor)
335 {
336     visitor->trace(m_owner);
337     visitor->trace(m_addTrackTracks);
338     visitor->trace(m_elementTracks);
339     visitor->trace(m_inbandTracks);
340 }