blob: b508dbed8b895f209f414288f12b978ad42d2d53 [file] [log] [blame]
/*
* Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#if ENABLE(VIDEO_TRACK)
#include "TrackListBase.h"
#include "EventNames.h"
#include "HTMLMediaElement.h"
#include "ScriptExecutionContext.h"
#include "TrackBase.h"
#include "TrackEvent.h"
using namespace WebCore;
TrackListBase::TrackListBase(HTMLMediaElement* element, ScriptExecutionContext* context)
: m_context(context)
, m_element(element)
, m_pendingEventTimer(this, &TrackListBase::asyncEventTimerFired)
, m_dispatchingEvents(0)
{
ASSERT(context->isDocument());
}
TrackListBase::~TrackListBase()
{
}
Element* TrackListBase::element() const
{
return m_element;
}
unsigned TrackListBase::length() const
{
return m_inbandTracks.size();
}
void TrackListBase::remove(TrackBase* track)
{
size_t index = m_inbandTracks.find(track);
ASSERT(index != notFound);
ASSERT(track->mediaElement() == m_element);
track->setMediaElement(0);
RefPtr<TrackBase> trackRef = m_inbandTracks[index];
m_inbandTracks.remove(index);
scheduleRemoveTrackEvent(trackRef.release());
}
bool TrackListBase::contains(TrackBase* track) const
{
return m_inbandTracks.find(track) != notFound;
}
void TrackListBase::scheduleAddTrackEvent(PassRefPtr<TrackBase> track)
{
// 4.8.10.5 Loading the media resource
// ...
// Fire a trusted event with the name addtrack, that does not bubble and is
// not cancelable, and that uses the TrackEvent interface, with the track
// attribute initialized to the new AudioTrack object, at this
// AudioTrackList object.
// ...
// Fire a trusted event with the name addtrack, that does not bubble and is
// not cancelable, and that uses the TrackEvent interface, with the track
// attribute initialized to the new VideoTrack object, at this
// VideoTrackList object.
// 4.8.10.12.3 Sourcing out-of-band text tracks
// 4.8.10.12.4 Text track API
// ... then queue a task to fire an event with the name addtrack, that does not
// bubble and is not cancelable, and that uses the TrackEvent interface, with
// the track attribute initialized to the text track's TextTrack object, at
// the media element's textTracks attribute's TextTrackList object.
RefPtr<TrackBase> trackRef = track;
TrackEventInit initializer;
initializer.track = trackRef;
initializer.bubbles = false;
initializer.cancelable = false;
m_pendingEvents.append(TrackEvent::create(eventNames().addtrackEvent, initializer));
if (!m_pendingEventTimer.isActive())
m_pendingEventTimer.startOneShot(0);
}
void TrackListBase::scheduleRemoveTrackEvent(PassRefPtr<TrackBase> track)
{
// 4.8.10.6 Offsets into the media resource
// If at any time the user agent learns that an audio or video track has
// ended and all media data relating to that track corresponds to parts of
// the media timeline that are before the earliest possible position, the
// user agent may queue a task to remove the track from the audioTracks
// attribute's AudioTrackList object or the videoTracks attribute's
// VideoTrackList object as appropriate and then fire a trusted event
// with the name removetrack, that does not bubble and is not cancelable,
// and that uses the TrackEvent interface, with the track attribute
// initialized to the AudioTrack or VideoTrack object representing the
// track, at the media element's aforementioned AudioTrackList or
// VideoTrackList object.
// 4.8.10.12.3 Sourcing out-of-band text tracks
// When a track element's parent element changes and the old parent was a
// media element, then the user agent must remove the track element's
// corresponding text track from the media element's list of text tracks,
// and then queue a task to fire a trusted event with the name removetrack,
// that does not bubble and is not cancelable, and that uses the TrackEvent
// interface, with the track attribute initialized to the text track's
// TextTrack object, at the media element's textTracks attribute's
// TextTrackList object.
RefPtr<TrackBase> trackRef = track;
TrackEventInit initializer;
initializer.track = trackRef;
initializer.bubbles = false;
initializer.cancelable = false;
m_pendingEvents.append(TrackEvent::create(eventNames().removetrackEvent, initializer));
if (!m_pendingEventTimer.isActive())
m_pendingEventTimer.startOneShot(0);
}
void TrackListBase::scheduleChangeEvent()
{
// 4.8.10.6 Offsets into the media resource
// Whenever an audio track in an AudioTrackList is enabled or disabled, the
// user agent must queue a task to fire a simple event named change at the
// AudioTrackList object.
// ...
// Whenever a track in a VideoTrackList that was previously not selected is
// selected, the user agent must queue a task to fire a simple event named
// change at the VideoTrackList object.
EventInit initializer;
initializer.bubbles = false;
initializer.cancelable = false;
m_pendingEvents.append(Event::create(eventNames().changeEvent, initializer));
if (!m_pendingEventTimer.isActive())
m_pendingEventTimer.startOneShot(0);
}
void TrackListBase::asyncEventTimerFired(Timer<TrackListBase>*)
{
Vector<RefPtr<Event>> pendingEvents;
++m_dispatchingEvents;
m_pendingEvents.swap(pendingEvents);
size_t count = pendingEvents.size();
for (size_t index = 0; index < count; ++index)
dispatchEvent(pendingEvents[index].release(), IGNORE_EXCEPTION);
--m_dispatchingEvents;
}
#endif