/* * 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