Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / 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 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 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
28 #if ENABLE(VIDEO_TRACK)
29
30 #include "TextTrackList.h"
31
32 #include "HTMLMediaElement.h"
33 #include "InbandTextTrack.h"
34 #include "InbandTextTrackPrivate.h"
35 #include "LoadableTextTrack.h"
36 #include <wtf/IsoMallocInlines.h>
37
38 namespace WebCore {
39
40 WTF_MAKE_ISO_ALLOCATED_IMPL(TextTrackList);
41
42 TextTrackList::TextTrackList(HTMLMediaElement* element, ScriptExecutionContext* context)
43     : TrackListBase(element, context)
44 {
45 }
46
47 TextTrackList::~TextTrackList()
48 {
49     clearElement();
50 }
51
52 void TextTrackList::clearElement()
53 {
54     TrackListBase::clearElement();
55     for (auto& track : m_elementTracks) {
56         track->setMediaElement(nullptr);
57         track->clearClient();
58     }
59     for (auto& track : m_addTrackTracks) {
60         track->setMediaElement(nullptr);
61         track->clearClient();
62     }
63 }
64
65 unsigned TextTrackList::length() const
66 {
67     return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
68 }
69
70 int TextTrackList::getTrackIndex(TextTrack& textTrack)
71 {
72     if (is<LoadableTextTrack>(textTrack))
73         return downcast<LoadableTextTrack>(textTrack).trackElementIndex();
74
75     if (textTrack.trackType() == TextTrack::AddTrack)
76         return m_elementTracks.size() + m_addTrackTracks.find(&textTrack);
77
78     if (textTrack.trackType() == TextTrack::InBand)
79         return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(&textTrack);
80
81     ASSERT_NOT_REACHED();
82
83     return -1;
84 }
85
86 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack& textTrack)
87 {
88     // 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."
89     int trackIndex = 0;
90
91     for (auto& elementTrack : m_elementTracks) {
92         if (!downcast<TextTrack>(*elementTrack).isRendered())
93             continue;
94         if (elementTrack == &textTrack)
95             return trackIndex;
96         ++trackIndex;
97     }
98
99     for (auto& addTrack : m_addTrackTracks) {
100         if (!downcast<TextTrack>(*addTrack).isRendered())
101             continue;
102         if (addTrack == &textTrack)
103             return trackIndex;
104         ++trackIndex;
105     }
106
107     for (auto& inbandTrack : m_inbandTracks) {
108         if (!downcast<TextTrack>(*inbandTrack).isRendered())
109             continue;
110         if (inbandTrack == &textTrack)
111             return trackIndex;
112         ++trackIndex;
113     }
114     ASSERT_NOT_REACHED();
115     return -1;
116 }
117
118 TextTrack* TextTrackList::item(unsigned index) const
119 {
120     // 4.8.10.12.1 Text track model
121     // The text tracks are sorted as follows:
122     // 1. The text tracks corresponding to track element children of the media element, in tree order.
123     // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
124     // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
125     // resource), in the order defined by the media resource's format specification.
126
127     if (index < m_elementTracks.size())
128         return downcast<TextTrack>(m_elementTracks[index].get());
129
130     index -= m_elementTracks.size();
131     if (index < m_addTrackTracks.size())
132         return downcast<TextTrack>(m_addTrackTracks[index].get());
133
134     index -= m_addTrackTracks.size();
135     if (index < m_inbandTracks.size())
136         return downcast<TextTrack>(m_inbandTracks[index].get());
137
138     return nullptr;
139 }
140
141 TextTrack* TextTrackList::getTrackById(const AtomString& id)
142 {
143     // 4.8.10.12.5 Text track API
144     // The getTrackById(id) method must return the first TextTrack in the
145     // TextTrackList object whose id IDL attribute would return a value equal
146     // to the value of the id argument.
147     for (unsigned i = 0; i < length(); ++i) {
148         auto& track = *item(i);
149         if (track.id() == id)
150             return &track;
151     }
152
153     // When no tracks match the given argument, the method must return null.
154     return nullptr;
155 }
156
157 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack& track)
158 {
159     Vector<RefPtr<TrackBase>>* tracks = nullptr;
160
161     switch (track.trackType()) {
162     case TextTrack::TrackElement:
163         tracks = &m_elementTracks;
164         for (auto& addTrack : m_addTrackTracks)
165             downcast<TextTrack>(addTrack.get())->invalidateTrackIndex();
166         for (auto& inbandTrack : m_inbandTracks)
167             downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
168         break;
169     case TextTrack::AddTrack:
170         tracks = &m_addTrackTracks;
171         for (auto& inbandTrack : m_inbandTracks)
172             downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
173         break;
174     case TextTrack::InBand:
175         tracks = &m_inbandTracks;
176         break;
177     default:
178         ASSERT_NOT_REACHED();
179     }
180
181     size_t index = tracks->find(&track);
182     if (index == notFound)
183         return;
184
185     for (size_t i = index; i < tracks->size(); ++i)
186         downcast<TextTrack>(*tracks->at(index)).invalidateTrackIndex();
187 }
188
189 void TextTrackList::append(Ref<TextTrack>&& track)
190 {
191     if (track->trackType() == TextTrack::AddTrack)
192         m_addTrackTracks.append(track.ptr());
193     else if (is<LoadableTextTrack>(track)) {
194         // Insert tracks added for <track> element in tree order.
195         size_t index = downcast<LoadableTextTrack>(track.get()).trackElementIndex();
196         m_elementTracks.insert(index, track.ptr());
197     } else if (track->trackType() == TextTrack::InBand) {
198         // Insert tracks added for in-band in the media file order.
199         size_t index = downcast<InbandTextTrack>(track.get()).inbandTrackIndex();
200         m_inbandTracks.insert(index, track.ptr());
201     } else
202         ASSERT_NOT_REACHED();
203
204     invalidateTrackIndexesAfterTrack(track);
205
206     ASSERT(!track->mediaElement() || track->mediaElement() == mediaElement());
207     track->setMediaElement(mediaElement());
208
209     scheduleAddTrackEvent(WTFMove(track));
210 }
211
212 void TextTrackList::remove(TrackBase& track, bool scheduleEvent)
213 {
214     auto& textTrack = downcast<TextTrack>(track);
215     Vector<RefPtr<TrackBase>>* tracks = nullptr;
216     switch (textTrack.trackType()) {
217     case TextTrack::TrackElement:
218         tracks = &m_elementTracks;
219         break;
220     case TextTrack::AddTrack:
221         tracks = &m_addTrackTracks;
222         break;
223     case TextTrack::InBand:
224         tracks = &m_inbandTracks;
225         break;
226     default:
227         ASSERT_NOT_REACHED();
228     }
229
230     size_t index = tracks->find(&track);
231     if (index == notFound)
232         return;
233
234     invalidateTrackIndexesAfterTrack(textTrack);
235
236     ASSERT(!track.mediaElement() || !element() || track.mediaElement() == element());
237     track.setMediaElement(nullptr);
238
239     Ref<TrackBase> trackRef = *(*tracks)[index];
240     tracks->remove(index);
241
242     if (scheduleEvent)
243         scheduleRemoveTrackEvent(WTFMove(trackRef));
244 }
245
246 bool TextTrackList::contains(TrackBase& track) const
247 {
248     const Vector<RefPtr<TrackBase>>* tracks = nullptr;
249     switch (downcast<TextTrack>(track).trackType()) {
250     case TextTrack::TrackElement:
251         tracks = &m_elementTracks;
252         break;
253     case TextTrack::AddTrack:
254         tracks = &m_addTrackTracks;
255         break;
256     case TextTrack::InBand:
257         tracks = &m_inbandTracks;
258         break;
259     default:
260         ASSERT_NOT_REACHED();
261     }
262     
263     return tracks->find(&track) != notFound;
264 }
265
266 EventTargetInterface TextTrackList::eventTargetInterface() const
267 {
268     return TextTrackListEventTargetInterfaceType;
269 }
270
271 const char* TextTrackList::activeDOMObjectName() const
272 {
273     return "TextTrackList";
274 }
275
276 } // namespace WebCore
277 #endif