Home | History | Annotate | Download | only in track
      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 
     51     // TextTrackList and m_asyncEventQueue always become unreachable
     52     // together. So TextTrackList and m_asyncEventQueue are destructed in the
     53     // same GC. We don't need to close it explicitly in Oilpan.
     54     m_asyncEventQueue->close();
     55 
     56     for (unsigned i = 0; i < length(); ++i) {
     57         item(i)->setTrackList(0);
     58     }
     59 #endif
     60 }
     61 
     62 unsigned TextTrackList::length() const
     63 {
     64     return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
     65 }
     66 
     67 int TextTrackList::getTrackIndex(TextTrack *textTrack)
     68 {
     69     if (textTrack->trackType() == TextTrack::TrackElement)
     70         return static_cast<LoadableTextTrack*>(textTrack)->trackElementIndex();
     71 
     72     if (textTrack->trackType() == TextTrack::AddTrack)
     73         return m_elementTracks.size() + m_addTrackTracks.find(textTrack);
     74 
     75     if (textTrack->trackType() == TextTrack::InBand)
     76         return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(textTrack);
     77 
     78     ASSERT_NOT_REACHED();
     79 
     80     return -1;
     81 }
     82 
     83 int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack *textTrack)
     84 {
     85     // 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."
     86     int trackIndex = 0;
     87 
     88     for (size_t i = 0; i < m_elementTracks.size(); ++i) {
     89         if (!m_elementTracks[i]->isRendered())
     90             continue;
     91 
     92         if (m_elementTracks[i] == textTrack)
     93             return trackIndex;
     94         ++trackIndex;
     95     }
     96 
     97     for (size_t i = 0; i < m_addTrackTracks.size(); ++i) {
     98         if (!m_addTrackTracks[i]->isRendered())
     99             continue;
    100 
    101         if (m_addTrackTracks[i] == textTrack)
    102             return trackIndex;
    103         ++trackIndex;
    104     }
    105 
    106     for (size_t i = 0; i < m_inbandTracks.size(); ++i) {
    107         if (!m_inbandTracks[i]->isRendered())
    108             continue;
    109 
    110         if (m_inbandTracks[i] == textTrack)
    111             return trackIndex;
    112         ++trackIndex;
    113     }
    114 
    115     ASSERT_NOT_REACHED();
    116 
    117     return -1;
    118 }
    119 
    120 TextTrack* TextTrackList::item(unsigned index)
    121 {
    122     // 4.8.10.12.1 Text track model
    123     // The text tracks are sorted as follows:
    124     // 1. The text tracks corresponding to track element children of the media element, in tree order.
    125     // 2. Any text tracks added using the addTextTrack() method, in the order they were added, oldest first.
    126     // 3. Any media-resource-specific text tracks (text tracks corresponding to data in the media
    127     // resource), in the order defined by the media resource's format specification.
    128 
    129     if (index < m_elementTracks.size())
    130         return m_elementTracks[index].get();
    131 
    132     index -= m_elementTracks.size();
    133     if (index < m_addTrackTracks.size())
    134         return m_addTrackTracks[index].get();
    135 
    136     index -= m_addTrackTracks.size();
    137     if (index < m_inbandTracks.size())
    138         return m_inbandTracks[index].get();
    139 
    140     return 0;
    141 }
    142 
    143 TextTrack* TextTrackList::getTrackById(const AtomicString& id)
    144 {
    145     // 4.8.10.12.5 Text track API
    146     // The getTrackById(id) method must return the first TextTrack in the
    147     // TextTrackList object whose id IDL attribute would return a value equal
    148     // to the value of the id argument.
    149     for (unsigned i = 0; i < length(); ++i) {
    150         TextTrack* track = item(i);
    151         if (track->id() == id)
    152             return track;
    153     }
    154 
    155     // When no tracks match the given argument, the method must return null.
    156     return 0;
    157 }
    158 
    159 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track)
    160 {
    161     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
    162 
    163     if (track->trackType() == TextTrack::TrackElement) {
    164         tracks = &m_elementTracks;
    165         for (size_t i = 0; i < m_addTrackTracks.size(); ++i)
    166             m_addTrackTracks[i]->invalidateTrackIndex();
    167         for (size_t i = 0; i < m_inbandTracks.size(); ++i)
    168             m_inbandTracks[i]->invalidateTrackIndex();
    169     } else if (track->trackType() == TextTrack::AddTrack) {
    170         tracks = &m_addTrackTracks;
    171         for (size_t i = 0; i < m_inbandTracks.size(); ++i)
    172             m_inbandTracks[i]->invalidateTrackIndex();
    173     } else if (track->trackType() == TextTrack::InBand)
    174         tracks = &m_inbandTracks;
    175     else
    176         ASSERT_NOT_REACHED();
    177 
    178     size_t index = tracks->find(track);
    179     if (index == kNotFound)
    180         return;
    181 
    182     for (size_t i = index; i < tracks->size(); ++i)
    183         tracks->at(index)->invalidateTrackIndex();
    184 }
    185 
    186 void TextTrackList::append(PassRefPtrWillBeRawPtr<TextTrack> prpTrack)
    187 {
    188     RefPtrWillBeRawPtr<TextTrack> track = prpTrack;
    189 
    190     if (track->trackType() == TextTrack::AddTrack)
    191         m_addTrackTracks.append(track);
    192     else if (track->trackType() == TextTrack::TrackElement) {
    193         // Insert tracks added for <track> element in tree order.
    194         size_t index = static_cast<LoadableTextTrack*>(track.get())->trackElementIndex();
    195         m_elementTracks.insert(index, track);
    196     } else if (track->trackType() == TextTrack::InBand) {
    197         // Insert tracks added for in-band in the media file order.
    198         size_t index = static_cast<InbandTextTrack*>(track.get())->inbandTrackIndex();
    199         m_inbandTracks.insert(index, track);
    200     } else
    201         ASSERT_NOT_REACHED();
    202 
    203     invalidateTrackIndexesAfterTrack(track.get());
    204 
    205     ASSERT(!track->trackList());
    206     track->setTrackList(this);
    207 
    208     scheduleAddTrackEvent(track.release());
    209 }
    210 
    211 void TextTrackList::remove(TextTrack* track)
    212 {
    213     WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
    214 
    215     if (track->trackType() == TextTrack::TrackElement) {
    216         tracks = &m_elementTracks;
    217     } else if (track->trackType() == TextTrack::AddTrack) {
    218         tracks = &m_addTrackTracks;
    219     } else if (track->trackType() == TextTrack::InBand) {
    220         tracks = &m_inbandTracks;
    221     } else {
    222         ASSERT_NOT_REACHED();
    223     }
    224 
    225     size_t index = tracks->find(track);
    226     if (index == kNotFound)
    227         return;
    228 
    229     invalidateTrackIndexesAfterTrack(track);
    230 
    231     ASSERT(track->trackList() == this);
    232     track->setTrackList(0);
    233 
    234     tracks->remove(index);
    235 
    236     scheduleRemoveTrackEvent(track);
    237 }
    238 
    239 void TextTrackList::removeAllInbandTracks()
    240 {
    241     for (unsigned i = 0; i < m_inbandTracks.size(); ++i) {
    242         m_inbandTracks[i]->setTrackList(0);
    243     }
    244     m_inbandTracks.clear();
    245 }
    246 
    247 bool TextTrackList::contains(TextTrack* track) const
    248 {
    249     const WillBeHeapVector<RefPtrWillBeMember<TextTrack> >* tracks = 0;
    250 
    251     if (track->trackType() == TextTrack::TrackElement)
    252         tracks = &m_elementTracks;
    253     else if (track->trackType() == TextTrack::AddTrack)
    254         tracks = &m_addTrackTracks;
    255     else if (track->trackType() == TextTrack::InBand)
    256         tracks = &m_inbandTracks;
    257     else
    258         ASSERT_NOT_REACHED();
    259 
    260     return tracks->find(track) != kNotFound;
    261 }
    262 
    263 const AtomicString& TextTrackList::interfaceName() const
    264 {
    265     return EventTargetNames::TextTrackList;
    266 }
    267 
    268 ExecutionContext* TextTrackList::executionContext() const
    269 {
    270     return m_owner ? m_owner->executionContext() : 0;
    271 }
    272 
    273 #if !ENABLE(OILPAN)
    274 void TextTrackList::clearOwner()
    275 {
    276     m_owner = nullptr;
    277 }
    278 #endif
    279 
    280 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, PassRefPtrWillBeRawPtr<TextTrack> track)
    281 {
    282     TrackEventInit initializer;
    283     initializer.track = track;
    284     initializer.bubbles = false;
    285     initializer.cancelable = false;
    286 
    287     m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, initializer));
    288 }
    289 
    290 void TextTrackList::scheduleAddTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
    291 {
    292     // 4.8.10.12.3 Sourcing out-of-band text tracks
    293     // 4.8.10.12.4 Text track API
    294     // ... then queue a task to fire an event with the name addtrack, that does not
    295     // bubble and is not cancelable, and that uses the TrackEvent interface, with
    296     // the track attribute initialized to the text track's TextTrack object, at
    297     // the media element's textTracks attribute's TextTrackList object.
    298     scheduleTrackEvent(EventTypeNames::addtrack, track);
    299 }
    300 
    301 void TextTrackList::scheduleChangeEvent()
    302 {
    303     // 4.8.10.12.1 Text track model
    304     // Whenever a text track that is in a media element's list of text tracks
    305     // has its text track mode change value, the user agent must run the
    306     // following steps for the media element:
    307     // ...
    308     // Fire a simple event named change at the media element's textTracks
    309     // attribute's TextTrackList object.
    310 
    311     EventInit initializer;
    312     initializer.bubbles = false;
    313     initializer.cancelable = false;
    314 
    315     m_asyncEventQueue->enqueueEvent(Event::create(EventTypeNames::change, initializer));
    316 }
    317 
    318 void TextTrackList::scheduleRemoveTrackEvent(PassRefPtrWillBeRawPtr<TextTrack> track)
    319 {
    320     // 4.8.10.12.3 Sourcing out-of-band text tracks
    321     // When a track element's parent element changes and the old parent was a
    322     // media element, then the user agent must remove the track element's
    323     // corresponding text track from the media element's list of text tracks,
    324     // and then queue a task to fire a trusted event with the name removetrack,
    325     // that does not bubble and is not cancelable, and that uses the TrackEvent
    326     // interface, with the track attribute initialized to the text track's
    327     // TextTrack object, at the media element's textTracks attribute's
    328     // TextTrackList object.
    329     scheduleTrackEvent(EventTypeNames::removetrack, track);
    330 }
    331 
    332 HTMLMediaElement* TextTrackList::owner() const
    333 {
    334     return m_owner;
    335 }
    336 
    337 void TextTrackList::trace(Visitor* visitor)
    338 {
    339     visitor->trace(m_owner);
    340     visitor->trace(m_asyncEventQueue);
    341     visitor->trace(m_addTrackTracks);
    342     visitor->trace(m_elementTracks);
    343     visitor->trace(m_inbandTracks);
    344     EventTargetWithInlineData::trace(visitor);
    345 }
    346