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 "TrackListBase.h"
31
32#include "EventNames.h"
33#include "HTMLMediaElement.h"
34#include "ScriptExecutionContext.h"
35#include "TrackEvent.h"
36
37using namespace WebCore;
38
39TrackListBase::TrackListBase(HTMLMediaElement* element, ScriptExecutionContext* context)
40    : m_context(context)
41    , m_element(element)
42    , m_asyncEventQueue(*this)
43{
44    ASSERT(context->isDocument());
45}
46
47TrackListBase::~TrackListBase()
48{
49}
50
51Element* TrackListBase::element() const
52{
53    return m_element;
54}
55
56unsigned TrackListBase::length() const
57{
58    return m_inbandTracks.size();
59}
60
61void TrackListBase::remove(TrackBase* track, bool scheduleEvent)
62{
63    size_t index = m_inbandTracks.find(track);
64    ASSERT(index != notFound);
65
66    ASSERT(track->mediaElement() == m_element);
67    track->setMediaElement(0);
68
69    RefPtr<TrackBase> trackRef = m_inbandTracks[index];
70
71    m_inbandTracks.remove(index);
72
73    if (scheduleEvent)
74        scheduleRemoveTrackEvent(trackRef.release());
75}
76
77bool TrackListBase::contains(TrackBase* track) const
78{
79    return m_inbandTracks.find(track) != notFound;
80}
81
82void TrackListBase::scheduleTrackEvent(const AtomicString& eventName, PassRefPtr<TrackBase> track)
83{
84    TrackEventInit initializer;
85    initializer.track = track;
86    initializer.bubbles = false;
87    initializer.cancelable = false;
88
89    m_asyncEventQueue.enqueueEvent(TrackEvent::create(eventName, initializer));
90}
91
92void TrackListBase::scheduleAddTrackEvent(PassRefPtr<TrackBase> track)
93{
94    // 4.8.10.5 Loading the media resource
95    // ...
96    // Fire a trusted event with the name addtrack, that does not bubble and is
97    // not cancelable, and that uses the TrackEvent interface, with the track
98    // attribute initialized to the new AudioTrack object, at this
99    // AudioTrackList object.
100    // ...
101    // Fire a trusted event with the name addtrack, that does not bubble and is
102    // not cancelable, and that uses the TrackEvent interface, with the track
103    // attribute initialized to the new VideoTrack object, at this
104    // VideoTrackList object.
105
106    // 4.8.10.12.3 Sourcing out-of-band text tracks
107    // 4.8.10.12.4 Text track API
108    // ... then queue a task to fire an event with the name addtrack, that does not
109    // bubble and is not cancelable, and that uses the TrackEvent interface, with
110    // the track attribute initialized to the text track's TextTrack object, at
111    // the media element's textTracks attribute's TextTrackList object.
112    scheduleTrackEvent(eventNames().addtrackEvent, track);
113}
114
115void TrackListBase::scheduleRemoveTrackEvent(PassRefPtr<TrackBase> track)
116{
117    // 4.8.10.6 Offsets into the media resource
118    // If at any time the user agent learns that an audio or video track has
119    // ended and all media data relating to that track corresponds to parts of
120    // the media timeline that are before the earliest possible position, the
121    // user agent may queue a task to remove the track from the audioTracks
122    // attribute's AudioTrackList object or the videoTracks attribute's
123    // VideoTrackList object as appropriate and then fire a trusted event
124    // with the name removetrack, that does not bubble and is not cancelable,
125    // and that uses the TrackEvent interface, with the track attribute
126    // initialized to the AudioTrack or VideoTrack object representing the
127    // track, at the media element's aforementioned AudioTrackList or
128    // VideoTrackList object.
129
130    // 4.8.10.12.3 Sourcing out-of-band text tracks
131    // When a track element's parent element changes and the old parent was a
132    // media element, then the user agent must remove the track element's
133    // corresponding text track from the media element's list of text tracks,
134    // and then queue a task to fire a trusted event with the name removetrack,
135    // that does not bubble and is not cancelable, and that uses the TrackEvent
136    // interface, with the track attribute initialized to the text track's
137    // TextTrack object, at the media element's textTracks attribute's
138    // TextTrackList object.
139    scheduleTrackEvent(eventNames().removetrackEvent, track);
140}
141
142void TrackListBase::scheduleChangeEvent()
143{
144    // 4.8.10.6 Offsets into the media resource
145    // Whenever an audio track in an AudioTrackList is enabled or disabled, the
146    // user agent must queue a task to fire a simple event named change at the
147    // AudioTrackList object.
148    // ...
149    // Whenever a track in a VideoTrackList that was previously not selected is
150    // selected, the user agent must queue a task to fire a simple event named
151    // change at the VideoTrackList object.
152
153    EventInit initializer;
154    initializer.bubbles = false;
155    initializer.cancelable = false;
156
157    m_asyncEventQueue.enqueueEvent(Event::create(eventNames().changeEvent, initializer));
158}
159
160bool TrackListBase::isAnyTrackEnabled() const
161{
162    for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
163        TrackBase* track = m_inbandTracks[i].get();
164        if (track->enabled())
165            return true;
166    }
167    return false;
168}
169
170#endif
171