#include "config.h"
#if ENABLE(VIDEO)
#include "TextTrackList.h"
#include "HTMLMediaElement.h"
#include "InbandTextTrack.h"
#include "InbandTextTrackPrivate.h"
#include "LoadableTextTrack.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(TextTrackList);
TextTrackList::TextTrackList(WeakPtr<HTMLMediaElement> element, ScriptExecutionContext* context)
: TrackListBase(element, context)
{
}
TextTrackList::~TextTrackList()
{
clearElement();
}
void TextTrackList::clearElement()
{
TrackListBase::clearElement();
for (auto& track : m_elementTracks) {
track->setMediaElement(nullptr);
track->clearClient();
}
for (auto& track : m_addTrackTracks) {
track->setMediaElement(nullptr);
track->clearClient();
}
}
unsigned TextTrackList::length() const
{
return m_addTrackTracks.size() + m_elementTracks.size() + m_inbandTracks.size();
}
int TextTrackList::getTrackIndex(TextTrack& textTrack)
{
if (is<LoadableTextTrack>(textTrack))
return downcast<LoadableTextTrack>(textTrack).trackElementIndex();
if (textTrack.trackType() == TextTrack::AddTrack)
return m_elementTracks.size() + m_addTrackTracks.find(&textTrack);
if (textTrack.trackType() == TextTrack::InBand)
return m_elementTracks.size() + m_addTrackTracks.size() + m_inbandTracks.find(&textTrack);
ASSERT_NOT_REACHED();
return -1;
}
int TextTrackList::getTrackIndexRelativeToRenderedTracks(TextTrack& textTrack)
{
int trackIndex = 0;
for (auto& elementTrack : m_elementTracks) {
if (!downcast<TextTrack>(*elementTrack).isRendered())
continue;
if (elementTrack == &textTrack)
return trackIndex;
++trackIndex;
}
for (auto& addTrack : m_addTrackTracks) {
if (!downcast<TextTrack>(*addTrack).isRendered())
continue;
if (addTrack == &textTrack)
return trackIndex;
++trackIndex;
}
for (auto& inbandTrack : m_inbandTracks) {
if (!downcast<TextTrack>(*inbandTrack).isRendered())
continue;
if (inbandTrack == &textTrack)
return trackIndex;
++trackIndex;
}
ASSERT_NOT_REACHED();
return -1;
}
TextTrack* TextTrackList::item(unsigned index) const
{
if (index < m_elementTracks.size())
return downcast<TextTrack>(m_elementTracks[index].get());
index -= m_elementTracks.size();
if (index < m_addTrackTracks.size())
return downcast<TextTrack>(m_addTrackTracks[index].get());
index -= m_addTrackTracks.size();
if (index < m_inbandTracks.size())
return downcast<TextTrack>(m_inbandTracks[index].get());
return nullptr;
}
TextTrack* TextTrackList::getTrackById(const AtomString& id)
{
for (unsigned i = 0; i < length(); ++i) {
auto& track = *item(i);
if (track.id() == id)
return &track;
}
return nullptr;
}
void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack& track)
{
Vector<RefPtr<TrackBase>>* tracks = nullptr;
switch (track.trackType()) {
case TextTrack::TrackElement:
tracks = &m_elementTracks;
for (auto& addTrack : m_addTrackTracks)
downcast<TextTrack>(addTrack.get())->invalidateTrackIndex();
for (auto& inbandTrack : m_inbandTracks)
downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
break;
case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
for (auto& inbandTrack : m_inbandTracks)
downcast<TextTrack>(inbandTrack.get())->invalidateTrackIndex();
break;
case TextTrack::InBand:
tracks = &m_inbandTracks;
break;
default:
ASSERT_NOT_REACHED();
}
size_t index = tracks->find(&track);
if (index == notFound)
return;
for (size_t i = index; i < tracks->size(); ++i)
downcast<TextTrack>(*tracks->at(index)).invalidateTrackIndex();
}
void TextTrackList::append(Ref<TextTrack>&& track)
{
if (track->trackType() == TextTrack::AddTrack)
m_addTrackTracks.append(track.ptr());
else if (is<LoadableTextTrack>(track)) {
size_t index = downcast<LoadableTextTrack>(track.get()).trackElementIndex();
m_elementTracks.insert(index, track.ptr());
} else if (track->trackType() == TextTrack::InBand) {
size_t index = downcast<InbandTextTrack>(track.get()).inbandTrackIndex();
m_inbandTracks.insert(index, track.ptr());
} else
ASSERT_NOT_REACHED();
invalidateTrackIndexesAfterTrack(track);
ASSERT(!track->mediaElement() || track->mediaElement() == mediaElement());
track->setMediaElement(mediaElement());
scheduleAddTrackEvent(WTFMove(track));
}
void TextTrackList::remove(TrackBase& track, bool scheduleEvent)
{
auto& textTrack = downcast<TextTrack>(track);
Vector<RefPtr<TrackBase>>* tracks = nullptr;
switch (textTrack.trackType()) {
case TextTrack::TrackElement:
tracks = &m_elementTracks;
break;
case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
break;
case TextTrack::InBand:
tracks = &m_inbandTracks;
break;
default:
ASSERT_NOT_REACHED();
}
size_t index = tracks->find(&track);
if (index == notFound)
return;
invalidateTrackIndexesAfterTrack(textTrack);
ASSERT(!track.mediaElement() || !element() || track.mediaElement() == element());
track.setMediaElement(nullptr);
Ref<TrackBase> trackRef = *(*tracks)[index];
tracks->remove(index);
if (scheduleEvent)
scheduleRemoveTrackEvent(WTFMove(trackRef));
}
bool TextTrackList::contains(TrackBase& track) const
{
const Vector<RefPtr<TrackBase>>* tracks = nullptr;
switch (downcast<TextTrack>(track).trackType()) {
case TextTrack::TrackElement:
tracks = &m_elementTracks;
break;
case TextTrack::AddTrack:
tracks = &m_addTrackTracks;
break;
case TextTrack::InBand:
tracks = &m_inbandTracks;
break;
default:
ASSERT_NOT_REACHED();
}
return tracks->find(&track) != notFound;
}
EventTargetInterface TextTrackList::eventTargetInterface() const
{
return TextTrackListEventTargetInterfaceType;
}
const char* TextTrackList::activeDOMObjectName() const
{
return "TextTrackList";
}
} #endif