blob: c1ca2a7652c24f02b16e86ad842b8f4a1285273e [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 "third_party/blink/renderer/core/html/track/text_track_list.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/track/inband_text_track.h"
#include "third_party/blink/renderer/core/html/track/loadable_text_track.h"
#include "third_party/blink/renderer/core/html/track/text_track.h"
#include "third_party/blink/renderer/core/html/track/track_event.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
TextTrackList::TextTrackList(HTMLMediaElement* owner) : owner_(owner) {}
TextTrackList::~TextTrackList() = default;
unsigned TextTrackList::length() const {
return add_track_tracks_.size() + element_tracks_.size() +
inband_tracks_.size();
}
int TextTrackList::GetTrackIndex(TextTrack* text_track) {
if (text_track->TrackType() == TextTrack::kTrackElement)
return ToLoadableTextTrack(text_track)->TrackElementIndex();
if (text_track->TrackType() == TextTrack::kAddTrack)
return element_tracks_.size() + add_track_tracks_.Find(text_track);
if (text_track->TrackType() == TextTrack::kInBand)
return element_tracks_.size() + add_track_tracks_.size() +
inband_tracks_.Find(text_track);
NOTREACHED();
return -1;
}
int TextTrackList::GetTrackIndexRelativeToRenderedTracks(
TextTrack* text_track) {
// 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."
int track_index = 0;
for (const auto& track : element_tracks_) {
if (!track->IsRendered())
continue;
if (track == text_track)
return track_index;
++track_index;
}
for (const auto& track : add_track_tracks_) {
if (!track->IsRendered())
continue;
if (track == text_track)
return track_index;
++track_index;
}
for (const auto& track : inband_tracks_) {
if (!track->IsRendered())
continue;
if (track == text_track)
return track_index;
++track_index;
}
NOTREACHED();
return -1;
}
TextTrack* TextTrackList::AnonymousIndexedGetter(unsigned index) {
// 4.8.10.12.1 Text track model
// The text tracks are sorted as follows:
// 1. The text tracks corresponding to track element children of the media
// element, in tree order.
// 2. Any text tracks added using the addTextTrack() method, in the order they
// were added, oldest first.
// 3. Any media-resource-specific text tracks (text tracks corresponding to
// data in the media resource), in the order defined by the media resource's
// format specification.
if (index < element_tracks_.size())
return element_tracks_[index];
index -= element_tracks_.size();
if (index < add_track_tracks_.size())
return add_track_tracks_[index];
index -= add_track_tracks_.size();
if (index < inband_tracks_.size())
return inband_tracks_[index];
return nullptr;
}
TextTrack* TextTrackList::getTrackById(const AtomicString& id) {
// 4.8.10.12.5 Text track API
// The getTrackById(id) method must return the first TextTrack in the
// TextTrackList object whose id IDL attribute would return a value equal
// to the value of the id argument.
for (unsigned i = 0; i < length(); ++i) {
TextTrack* track = AnonymousIndexedGetter(i);
if (String(track->id()) == id)
return track;
}
// When no tracks match the given argument, the method must return null.
return nullptr;
}
void TextTrackList::InvalidateTrackIndexesAfterTrack(TextTrack* track) {
HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
if (track->TrackType() == TextTrack::kTrackElement) {
tracks = &element_tracks_;
for (const auto& add_track : add_track_tracks_)
add_track->InvalidateTrackIndex();
for (const auto& inband_track : inband_tracks_)
inband_track->InvalidateTrackIndex();
} else if (track->TrackType() == TextTrack::kAddTrack) {
tracks = &add_track_tracks_;
for (const auto& inband_track : inband_tracks_)
inband_track->InvalidateTrackIndex();
} else if (track->TrackType() == TextTrack::kInBand) {
tracks = &inband_tracks_;
} else {
NOTREACHED();
}
wtf_size_t index = tracks->Find(track);
if (index == kNotFound)
return;
for (wtf_size_t i = index; i < tracks->size(); ++i)
tracks->at(i)->InvalidateTrackIndex();
}
void TextTrackList::Append(TextTrack* track) {
if (track->TrackType() == TextTrack::kAddTrack) {
add_track_tracks_.push_back(track);
} else if (track->TrackType() == TextTrack::kTrackElement) {
// Insert tracks added for <track> element in tree order.
wtf_size_t index = ToLoadableTextTrack(track)->TrackElementIndex();
element_tracks_.insert(index, track);
} else if (track->TrackType() == TextTrack::kInBand) {
inband_tracks_.push_back(track);
} else {
NOTREACHED();
}
InvalidateTrackIndexesAfterTrack(track);
DCHECK(!track->TrackList());
track->SetTrackList(this);
ScheduleAddTrackEvent(track);
}
void TextTrackList::Remove(TextTrack* track) {
HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
if (track->TrackType() == TextTrack::kTrackElement) {
tracks = &element_tracks_;
} else if (track->TrackType() == TextTrack::kAddTrack) {
tracks = &add_track_tracks_;
} else if (track->TrackType() == TextTrack::kInBand) {
tracks = &inband_tracks_;
} else {
NOTREACHED();
}
wtf_size_t index = tracks->Find(track);
if (index == kNotFound)
return;
InvalidateTrackIndexesAfterTrack(track);
DCHECK_EQ(track->TrackList(), this);
track->SetTrackList(nullptr);
tracks->EraseAt(index);
ScheduleRemoveTrackEvent(track);
}
void TextTrackList::RemoveAllInbandTracks() {
for (const auto& track : inband_tracks_) {
track->SetTrackList(nullptr);
}
inband_tracks_.clear();
}
bool TextTrackList::Contains(TextTrack* track) const {
const HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
if (track->TrackType() == TextTrack::kTrackElement)
tracks = &element_tracks_;
else if (track->TrackType() == TextTrack::kAddTrack)
tracks = &add_track_tracks_;
else if (track->TrackType() == TextTrack::kInBand)
tracks = &inband_tracks_;
else
NOTREACHED();
return tracks->Find(track) != kNotFound;
}
const AtomicString& TextTrackList::InterfaceName() const {
return event_target_names::kTextTrackList;
}
ExecutionContext* TextTrackList::GetExecutionContext() const {
return owner_ ? owner_->GetExecutionContext() : nullptr;
}
void TextTrackList::ScheduleTrackEvent(const AtomicString& event_name,
TextTrack* track) {
EnqueueEvent(*TrackEvent::Create(event_name, track),
TaskType::kMediaElementEvent);
}
void TextTrackList::ScheduleAddTrackEvent(TextTrack* track) {
// 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.
ScheduleTrackEvent(event_type_names::kAddtrack, track);
}
void TextTrackList::ScheduleChangeEvent() {
// 4.8.10.12.1 Text track model
// Whenever a text track that is in a media element's list of text tracks
// has its text track mode change value, the user agent must run the
// following steps for the media element:
// ...
// Fire a simple event named change at the media element's textTracks
// attribute's TextTrackList object.
EnqueueEvent(*Event::Create(event_type_names::kChange),
TaskType::kMediaElementEvent);
}
void TextTrackList::ScheduleRemoveTrackEvent(TextTrack* track) {
// 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.
ScheduleTrackEvent(event_type_names::kRemovetrack, track);
}
bool TextTrackList::HasShowingTracks() {
for (unsigned i = 0; i < length(); ++i) {
if (AnonymousIndexedGetter(i)->mode() == TextTrack::ShowingKeyword())
return true;
}
return false;
}
HTMLMediaElement* TextTrackList::Owner() const {
return owner_;
}
void TextTrackList::Trace(Visitor* visitor) {
visitor->Trace(owner_);
visitor->Trace(add_track_tracks_);
visitor->Trace(element_tracks_);
visitor->Trace(inband_tracks_);
EventTargetWithInlineData::Trace(visitor);
}
} // namespace blink