michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/TextTrackList.h" michael@0: #include "mozilla/dom/TextTrackListBinding.h" michael@0: #include "mozilla/dom/TrackEvent.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/dom/TextTrackCue.h" michael@0: #include "mozilla/dom/TextTrackManager.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrackList, michael@0: DOMEventTargetHelper, michael@0: mTextTracks, michael@0: mTextTrackManager) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(TextTrackList, DOMEventTargetHelper) michael@0: NS_IMPL_RELEASE_INHERITED(TextTrackList, DOMEventTargetHelper) michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrackList) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) michael@0: michael@0: TextTrackList::TextTrackList(nsPIDOMWindow* aOwnerWindow) michael@0: : DOMEventTargetHelper(aOwnerWindow) michael@0: { michael@0: } michael@0: michael@0: TextTrackList::TextTrackList(nsPIDOMWindow* aOwnerWindow, michael@0: TextTrackManager* aTextTrackManager) michael@0: : DOMEventTargetHelper(aOwnerWindow) michael@0: , mTextTrackManager(aTextTrackManager) michael@0: { michael@0: } michael@0: michael@0: void michael@0: TextTrackList::UpdateAndGetShowingCues(nsTArray >& aCues) michael@0: { michael@0: nsTArray< nsRefPtr > cues; michael@0: for (uint32_t i = 0; i < Length(); i++) { michael@0: TextTrackMode mode = mTextTracks[i]->Mode(); michael@0: // If the mode is hidden then we just need to update the active cue list, michael@0: // we don't need to show it on the video. michael@0: if (mode == TextTrackMode::Hidden) { michael@0: mTextTracks[i]->UpdateActiveCueList(); michael@0: } else if (mode == TextTrackMode::Showing) { michael@0: // If the mode is showing then we need to update the cue list and show it michael@0: // on the video. GetActiveCueArray() calls UpdateActiveCueList() so we michael@0: // don't need to call it explicitly. michael@0: mTextTracks[i]->GetActiveCueArray(cues); michael@0: aCues.AppendElements(cues); michael@0: } michael@0: } michael@0: } michael@0: michael@0: JSObject* michael@0: TextTrackList::WrapObject(JSContext* aCx) michael@0: { michael@0: return TextTrackListBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: TextTrack* michael@0: TextTrackList::IndexedGetter(uint32_t aIndex, bool& aFound) michael@0: { michael@0: aFound = aIndex < mTextTracks.Length(); michael@0: return aFound ? mTextTracks[aIndex] : nullptr; michael@0: } michael@0: michael@0: TextTrack* michael@0: TextTrackList::operator[](uint32_t aIndex) michael@0: { michael@0: return mTextTracks.SafeElementAt(aIndex, nullptr); michael@0: } michael@0: michael@0: already_AddRefed michael@0: TextTrackList::AddTextTrack(TextTrackKind aKind, michael@0: const nsAString& aLabel, michael@0: const nsAString& aLanguage, michael@0: TextTrackMode aMode, michael@0: TextTrackReadyState aReadyState, michael@0: TextTrackSource aTextTrackSource, michael@0: const CompareTextTracks& aCompareTT) michael@0: { michael@0: nsRefPtr track = new TextTrack(GetOwner(), this, aKind, aLabel, michael@0: aLanguage, aMode, aReadyState, michael@0: aTextTrackSource); michael@0: AddTextTrack(track, aCompareTT); michael@0: return track.forget(); michael@0: } michael@0: michael@0: void michael@0: TextTrackList::AddTextTrack(TextTrack* aTextTrack, michael@0: const CompareTextTracks& aCompareTT) michael@0: { michael@0: if (mTextTracks.InsertElementSorted(aTextTrack, aCompareTT)) { michael@0: aTextTrack->SetTextTrackList(this); michael@0: CreateAndDispatchTrackEventRunner(aTextTrack, NS_LITERAL_STRING("addtrack")); michael@0: } michael@0: } michael@0: michael@0: TextTrack* michael@0: TextTrackList::GetTrackById(const nsAString& aId) michael@0: { michael@0: nsAutoString id; michael@0: for (uint32_t i = 0; i < Length(); i++) { michael@0: mTextTracks[i]->GetId(id); michael@0: if (aId.Equals(id)) { michael@0: return mTextTracks[i]; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: TextTrackList::RemoveTextTrack(TextTrack* aTrack) michael@0: { michael@0: if (mTextTracks.RemoveElement(aTrack)) { michael@0: CreateAndDispatchTrackEventRunner(aTrack, NS_LITERAL_STRING("removetrack")); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextTrackList::DidSeek() michael@0: { michael@0: for (uint32_t i = 0; i < mTextTracks.Length(); i++) { michael@0: mTextTracks[i]->SetDirty(); michael@0: } michael@0: } michael@0: michael@0: class TrackEventRunner MOZ_FINAL: public nsRunnable michael@0: { michael@0: public: michael@0: TrackEventRunner(TextTrackList* aList, nsIDOMEvent* aEvent) michael@0: : mList(aList) michael@0: , mEvent(aEvent) michael@0: {} michael@0: michael@0: NS_IMETHOD Run() MOZ_OVERRIDE michael@0: { michael@0: return mList->DispatchTrackEvent(mEvent); michael@0: } michael@0: michael@0: private: michael@0: nsRefPtr mList; michael@0: nsRefPtr mEvent; michael@0: }; michael@0: michael@0: nsresult michael@0: TextTrackList::DispatchTrackEvent(nsIDOMEvent* aEvent) michael@0: { michael@0: return DispatchTrustedEvent(aEvent); michael@0: } michael@0: michael@0: void michael@0: TextTrackList::CreateAndDispatchChangeEvent() michael@0: { michael@0: nsCOMPtr event; michael@0: nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Failed to create the error event!"); michael@0: return; michael@0: } michael@0: michael@0: rv = event->InitEvent(NS_LITERAL_STRING("change"), false, false); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("Failed to init the change event!"); michael@0: return; michael@0: } michael@0: michael@0: event->SetTrusted(true); michael@0: michael@0: nsCOMPtr eventRunner = new TrackEventRunner(this, event); michael@0: NS_DispatchToMainThread(eventRunner, NS_DISPATCH_NORMAL); michael@0: } michael@0: michael@0: void michael@0: TextTrackList::CreateAndDispatchTrackEventRunner(TextTrack* aTrack, michael@0: const nsAString& aEventName) michael@0: { michael@0: TrackEventInit eventInit; michael@0: eventInit.mBubbles = false; michael@0: eventInit.mCancelable = false; michael@0: eventInit.mTrack = aTrack; michael@0: nsRefPtr event = michael@0: TrackEvent::Constructor(this, aEventName, eventInit); michael@0: michael@0: // Dispatch the TrackEvent asynchronously. michael@0: nsCOMPtr eventRunner = new TrackEventRunner(this, event); michael@0: NS_DispatchToMainThread(eventRunner, NS_DISPATCH_NORMAL); michael@0: } michael@0: michael@0: HTMLMediaElement* michael@0: TextTrackList::GetMediaElement() michael@0: { michael@0: if (mTextTrackManager) { michael@0: return mTextTrackManager->mMediaElement; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: void michael@0: TextTrackList::SetTextTrackManager(TextTrackManager* aTextTrackManager) michael@0: { michael@0: mTextTrackManager = aTextTrackManager; michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla