Bug 883173 - Part 3: Implement TextTrack::ActiveCues. r=cpearce, r=rillian

- Active cues now returns the subset of cues in mCueList that are valid
for the current playback time.
- Introduces new code in media element, when seeking, and in TextTrack, when
adding and removing cues, to mark the active cue list as dirty so that we know
when we might need to rebuild the list completely.
This commit is contained in:
Rick Eyre 2013-06-14 16:10:36 -04:00
parent cc4dfddc6f
commit 7141a09f73
8 changed files with 129 additions and 29 deletions

View File

@ -2938,6 +2938,7 @@ void HTMLMediaElement::SeekCompleted()
DispatchAsyncEvent(NS_LITERAL_STRING("seeked"));
// We changed whether we're seeking so we need to AddRemoveSelfReference
AddRemoveSelfReference();
mTextTracks->DidSeek();
}
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
@ -3866,7 +3867,7 @@ HTMLMediaElement::AddTextTrack(TextTrackKind aKind,
const nsAString& aLabel,
const nsAString& aLanguage)
{
return mTextTracks->AddTextTrack(aKind, aLabel, aLanguage);
return mTextTracks->AddTextTrack(this, aKind, aLabel, aLanguage);
}
} // namespace dom

View File

@ -126,7 +126,7 @@ HTMLTrackElement::Track()
if (!mTrack) {
// We're expected to always have an internal TextTrack so create
// an empty object to return if we don't already have one.
mTrack = new TextTrack(OwnerDoc()->GetParentObject());
mTrack = new TextTrack(OwnerDoc()->GetParentObject(), mMediaParent);
}
return mTrack;
@ -146,7 +146,8 @@ HTMLTrackElement::CreateTextTrack()
kind = TextTrackKind::Subtitles;
}
mTrack = new TextTrack(OwnerDoc()->GetParentObject(), kind, label, srcLang);
mTrack = new TextTrack(OwnerDoc()->GetParentObject(), mMediaParent, kind,
label, srcLang);
if (mMediaParent) {
mMediaParent->AddTextTrack(mTrack);

View File

@ -6,16 +6,19 @@
#include "mozilla/dom/TextTrack.h"
#include "mozilla/dom/TextTrackBinding.h"
#include "mozilla/dom/TextTrackCue.h"
#include "mozilla/dom/TextTrackCueList.h"
#include "mozilla/dom/TextTrackRegion.h"
#include "mozilla/dom/TextTrackRegionList.h"
#include "mozilla/dom/HTMLMediaElement.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED_4(TextTrack,
NS_IMPL_CYCLE_COLLECTION_INHERITED_5(TextTrack,
nsDOMEventTargetHelper,
mParent,
mMediaElement,
mCueList,
mActiveCueList,
mRegionList)
@ -25,31 +28,46 @@ NS_IMPL_RELEASE_INHERITED(TextTrack, nsDOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrack)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
TextTrack::TextTrack(nsISupports* aParent)
: mParent(aParent)
{
SetDefaultSettings();
SetIsDOMBinding();
}
TextTrack::TextTrack(nsISupports* aParent, HTMLMediaElement* aMediaElement)
: mParent(aParent)
, mMediaElement(aMediaElement)
{
SetDefaultSettings();
SetIsDOMBinding();
}
TextTrack::TextTrack(nsISupports* aParent,
HTMLMediaElement* aMediaElement,
TextTrackKind aKind,
const nsAString& aLabel,
const nsAString& aLanguage)
: mParent(aParent)
, mKind(aKind)
, mLabel(aLabel)
, mLanguage(aLanguage)
, mMode(TextTrackMode::Hidden)
, mCueList(new TextTrackCueList(aParent))
, mActiveCueList(new TextTrackCueList(aParent))
, mRegionList(new TextTrackRegionList(aParent))
, mMediaElement(aMediaElement)
{
SetDefaultSettings();
mKind = aKind;
mLabel = aLabel;
mLanguage = aLanguage;
SetIsDOMBinding();
}
TextTrack::TextTrack(nsISupports* aParent)
: mParent(aParent)
, mKind(TextTrackKind::Subtitles)
, mMode(TextTrackMode::Disabled)
, mCueList(new TextTrackCueList(aParent))
, mActiveCueList(new TextTrackCueList(aParent))
, mRegionList(new TextTrackRegionList(aParent))
void
TextTrack::SetDefaultSettings()
{
SetIsDOMBinding();
mKind = TextTrackKind::Subtitles;
mMode = TextTrackMode::Hidden;
mCueList = new TextTrackCueList(mParent);
mActiveCueList = new TextTrackCueList(mParent);
mRegionList = new TextTrackRegionList(mParent);
mCuePos = 0;
mDirty = false;
}
void
@ -74,12 +92,14 @@ void
TextTrack::AddCue(TextTrackCue& aCue)
{
mCueList->AddCue(aCue);
SetDirty();
}
void
TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
{
mCueList->RemoveCue(aCue, aRv);
SetDirty();
}
void
@ -111,5 +131,43 @@ TextTrack::RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv)
mRegionList->RemoveTextTrackRegion(aRegion);
}
TextTrackCueList*
TextTrack::GetActiveCues()
{
if (mMode == TextTrackMode::Disabled || !mMediaElement) {
return nullptr;
}
// If we are dirty, i.e. an event happened that may cause the sorted mCueList
// to have changed like a seek or an insert for a cue, than we need to rebuild
// the active cue list from scratch.
if (mDirty) {
mCuePos = 0;
mDirty = true;
mActiveCueList->RemoveAll();
}
double playbackTime = mMediaElement->CurrentTime();
// Remove all the cues from the active cue list whose end times now occur
// earlier then the current playback time. When we reach a cue whose end time
// is valid we can safely stop iterating as the list is sorted.
for (uint32_t i = 0; i < mActiveCueList->Length() &&
(*mActiveCueList)[i]->EndTime() < playbackTime; i++) {
mActiveCueList->RemoveCueAt(i);
}
// Add all the cues, starting from the position of the last cue that was
// added, that have valid start and end times for the current playback time.
// We can stop iterating safely once we encounter a cue that does not have
// valid times for the current playback time as the cue list is sorted.
for (; mCuePos < mCueList->Length(); mCuePos++) {
TextTrackCue* cue = (*mCueList)[mCuePos];
if (cue->StartTime() > playbackTime || cue->EndTime() < playbackTime) {
break;
}
mActiveCueList->AddCue(*cue);
}
return mActiveCueList;
}
} // namespace dom
} // namespace mozilla

View File

@ -20,6 +20,7 @@ class TextTrackCue;
class TextTrackCueList;
class TextTrackRegion;
class TextTrackRegionList;
class HTMLMediaElement;
class TextTrack MOZ_FINAL : public nsDOMEventTargetHelper
{
@ -29,10 +30,15 @@ public:
TextTrack(nsISupports* aParent);
TextTrack(nsISupports* aParent,
HTMLMediaElement* aMediaElement);
TextTrack(nsISupports* aParent,
HTMLMediaElement* aMediaElement,
TextTrackKind aKind,
const nsAString& aLabel,
const nsAString& aLanguage);
void SetDefaultSettings();
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@ -76,13 +82,7 @@ public:
return mCueList;
}
TextTrackCueList* GetActiveCues() const
{
if (mMode == TextTrackMode::Disabled) {
return nullptr;
}
return mActiveCueList;
}
TextTrackCueList* GetActiveCues();
TextTrackRegionList* GetRegions() const
{
@ -101,11 +101,13 @@ public:
void AddCue(TextTrackCue& aCue);
void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
void CueChanged(TextTrackCue& aCue);
void SetDirty() { mDirty = true; }
IMPL_EVENT_HANDLER(cuechange)
private:
nsCOMPtr<nsISupports> mParent;
nsRefPtr<HTMLMediaElement> mMediaElement;
TextTrackKind mKind;
nsString mLabel;
@ -117,6 +119,9 @@ private:
nsRefPtr<TextTrackCueList> mCueList;
nsRefPtr<TextTrackCueList> mActiveCueList;
nsRefPtr<TextTrackRegionList> mRegionList;
uint32_t mCuePos;
bool mDirty;
};
} // namespace dom

View File

@ -62,6 +62,12 @@ TextTrackCueList::IndexedGetter(uint32_t aIndex, bool& aFound)
return aFound ? mList[aIndex] : nullptr;
}
TextTrackCue*
TextTrackCueList::operator[](uint32_t aIndex)
{
return mList.SafeElementAt(aIndex, nullptr);
}
TextTrackCue*
TextTrackCueList::GetCueById(const nsAString& aId)
{
@ -96,5 +102,19 @@ TextTrackCueList::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
mList.RemoveElement(&aCue);
}
void
TextTrackCueList::RemoveCueAt(uint32_t aIndex)
{
if (aIndex < mList.Length()) {
mList.RemoveElementAt(aIndex);
}
}
void
TextTrackCueList::RemoveAll()
{
mList.Clear();
}
} // namespace dom
} // namespace mozilla

View File

@ -45,6 +45,7 @@ public:
void Update(double aTime);
TextTrackCue* IndexedGetter(uint32_t aIndex, bool& aFound);
TextTrackCue* operator[](uint32_t aIndex);
TextTrackCue* GetCueById(const nsAString& aId);
// Adds a cue to mList by performing an insertion sort on mList.
@ -53,6 +54,8 @@ public:
// sort step after all cues are loaded.
void AddCue(TextTrackCue& aCue);
void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
void RemoveCueAt(uint32_t aIndex);
void RemoveAll();
private:
nsCOMPtr<nsISupports> mParent;

View File

@ -47,11 +47,13 @@ TextTrackList::IndexedGetter(uint32_t aIndex, bool& aFound)
}
already_AddRefed<TextTrack>
TextTrackList::AddTextTrack(TextTrackKind aKind,
TextTrackList::AddTextTrack(HTMLMediaElement* aMediaElement,
TextTrackKind aKind,
const nsAString& aLabel,
const nsAString& aLanguage)
{
nsRefPtr<TextTrack> track = new TextTrack(mGlobal, aKind, aLabel, aLanguage);
nsRefPtr<TextTrack> track = new TextTrack(mGlobal, aMediaElement, aKind,
aLabel, aLanguage);
mTextTracks.AppendElement(track);
// TODO: dispatch addtrack event
return track.forget();
@ -76,5 +78,13 @@ TextTrackList::RemoveTextTrack(const TextTrack& aTrack)
mTextTracks.RemoveElement(&aTrack);
}
void
TextTrackList::DidSeek()
{
for (uint32_t i = 0; i < mTextTracks.Length(); i++) {
mTextTracks[i]->SetDirty();
}
}
} // namespace dom
} // namespace mozilla

View File

@ -40,7 +40,8 @@ public:
TextTrack* IndexedGetter(uint32_t aIndex, bool& aFound);
already_AddRefed<TextTrack> AddTextTrack(TextTrackKind aKind,
already_AddRefed<TextTrack> AddTextTrack(HTMLMediaElement* aMediaElement,
TextTrackKind aKind,
const nsAString& aLabel,
const nsAString& aLanguage);
TextTrack* GetTrackById(const nsAString& aId);
@ -50,6 +51,7 @@ public:
}
void RemoveTextTrack(const TextTrack& aTrack);
void DidSeek();
IMPL_EVENT_HANDLER(addtrack)
IMPL_EVENT_HANDLER(removetrack)