Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 et tw=78: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/AsyncEventDispatcher.h"
8 : #include "mozilla/dom/TextTrack.h"
9 : #include "mozilla/dom/TextTrackBinding.h"
10 : #include "mozilla/dom/TextTrackList.h"
11 : #include "mozilla/dom/TextTrackCue.h"
12 : #include "mozilla/dom/TextTrackCueList.h"
13 : #include "mozilla/dom/TextTrackRegion.h"
14 : #include "mozilla/dom/HTMLMediaElement.h"
15 : #include "mozilla/dom/HTMLTrackElement.h"
16 : #include "nsGlobalWindow.h"
17 :
18 : namespace mozilla {
19 : namespace dom {
20 :
21 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrack,
22 : DOMEventTargetHelper,
23 : mCueList,
24 : mActiveCueList,
25 : mTextTrackList,
26 : mTrackElement)
27 :
28 0 : NS_IMPL_ADDREF_INHERITED(TextTrack, DOMEventTargetHelper)
29 0 : NS_IMPL_RELEASE_INHERITED(TextTrack, DOMEventTargetHelper)
30 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TextTrack)
31 0 : NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
32 :
33 0 : TextTrack::TextTrack(nsPIDOMWindowInner* aOwnerWindow,
34 : TextTrackKind aKind,
35 : const nsAString& aLabel,
36 : const nsAString& aLanguage,
37 : TextTrackMode aMode,
38 : TextTrackReadyState aReadyState,
39 0 : TextTrackSource aTextTrackSource)
40 : : DOMEventTargetHelper(aOwnerWindow)
41 : , mKind(aKind)
42 : , mLabel(aLabel)
43 : , mLanguage(aLanguage)
44 : , mMode(aMode)
45 : , mReadyState(aReadyState)
46 0 : , mTextTrackSource(aTextTrackSource)
47 : {
48 0 : SetDefaultSettings();
49 0 : }
50 :
51 0 : TextTrack::TextTrack(nsPIDOMWindowInner* aOwnerWindow,
52 : TextTrackList* aTextTrackList,
53 : TextTrackKind aKind,
54 : const nsAString& aLabel,
55 : const nsAString& aLanguage,
56 : TextTrackMode aMode,
57 : TextTrackReadyState aReadyState,
58 0 : TextTrackSource aTextTrackSource)
59 : : DOMEventTargetHelper(aOwnerWindow)
60 : , mTextTrackList(aTextTrackList)
61 : , mKind(aKind)
62 : , mLabel(aLabel)
63 : , mLanguage(aLanguage)
64 : , mMode(aMode)
65 : , mReadyState(aReadyState)
66 0 : , mTextTrackSource(aTextTrackSource)
67 : {
68 0 : SetDefaultSettings();
69 0 : }
70 :
71 0 : TextTrack::~TextTrack()
72 : {
73 0 : }
74 :
75 : void
76 0 : TextTrack::SetDefaultSettings()
77 : {
78 0 : nsPIDOMWindowInner* ownerWindow = GetOwner();
79 0 : mCueList = new TextTrackCueList(ownerWindow);
80 0 : mActiveCueList = new TextTrackCueList(ownerWindow);
81 0 : mCuePos = 0;
82 0 : mDirty = false;
83 0 : }
84 :
85 : JSObject*
86 0 : TextTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
87 : {
88 0 : return TextTrackBinding::Wrap(aCx, this, aGivenProto);
89 : }
90 :
91 : void
92 0 : TextTrack::SetMode(TextTrackMode aValue)
93 : {
94 0 : if (mMode != aValue) {
95 0 : mMode = aValue;
96 0 : if (aValue == TextTrackMode::Disabled) {
97 : // Remove all the cues in MediaElement.
98 0 : if (mTextTrackList) {
99 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
100 0 : if (mediaElement) {
101 0 : for (size_t i = 0; i < mCueList->Length(); ++i) {
102 0 : mediaElement->NotifyCueRemoved(*(*mCueList)[i]);
103 : }
104 : }
105 : }
106 0 : SetCuesInactive();
107 : } else {
108 : // Add all the cues into MediaElement.
109 0 : if (mTextTrackList) {
110 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
111 0 : if (mediaElement) {
112 0 : for (size_t i = 0; i < mCueList->Length(); ++i) {
113 0 : mediaElement->NotifyCueAdded(*(*mCueList)[i]);
114 : }
115 : }
116 : }
117 : }
118 0 : if (mTextTrackList) {
119 0 : mTextTrackList->CreateAndDispatchChangeEvent();
120 : }
121 : // Ensure the TimeMarchesOn is called in case that the mCueList
122 : // is empty.
123 0 : NotifyCueUpdated(nullptr);
124 : }
125 0 : }
126 :
127 : void
128 0 : TextTrack::GetId(nsAString& aId) const
129 : {
130 : // If the track has a track element then its id should be the same as the
131 : // track element's id.
132 0 : if (mTrackElement) {
133 0 : mTrackElement->GetAttribute(NS_LITERAL_STRING("id"), aId);
134 : }
135 0 : }
136 :
137 : void
138 0 : TextTrack::AddCue(TextTrackCue& aCue)
139 : {
140 0 : TextTrack* oldTextTrack = aCue.GetTrack();
141 0 : if (oldTextTrack) {
142 0 : ErrorResult dummy;
143 0 : oldTextTrack->RemoveCue(aCue, dummy);
144 : }
145 0 : mCueList->AddCue(aCue);
146 0 : aCue.SetTrack(this);
147 0 : if (mTextTrackList) {
148 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
149 0 : if (mediaElement && (mMode != TextTrackMode::Disabled)) {
150 0 : mediaElement->NotifyCueAdded(aCue);
151 : }
152 : }
153 0 : SetDirty();
154 0 : }
155 :
156 : void
157 0 : TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
158 : {
159 : // Bug1304948, check the aCue belongs to the TextTrack.
160 0 : mCueList->RemoveCue(aCue, aRv);
161 0 : if (aRv.Failed()) {
162 0 : return;
163 : }
164 0 : aCue.SetActive(false);
165 0 : aCue.SetTrack(nullptr);
166 0 : if (mTextTrackList) {
167 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
168 0 : if (mediaElement) {
169 0 : mediaElement->NotifyCueRemoved(aCue);
170 : }
171 : }
172 0 : SetDirty();
173 : }
174 :
175 : void
176 0 : TextTrack::SetCuesDirty()
177 : {
178 0 : for (uint32_t i = 0; i < mCueList->Length(); i++) {
179 0 : ((*mCueList)[i])->Reset();
180 : }
181 0 : }
182 :
183 : void
184 0 : TextTrack::UpdateActiveCueList()
185 : {
186 0 : if (!mTextTrackList) {
187 0 : return;
188 : }
189 :
190 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
191 0 : if (!mediaElement) {
192 0 : return;
193 : }
194 :
195 : // If we are dirty, i.e. an event happened that may cause the sorted mCueList
196 : // to have changed like a seek or an insert for a cue, than we need to rebuild
197 : // the active cue list from scratch.
198 0 : if (mDirty) {
199 0 : mCuePos = 0;
200 0 : mDirty = false;
201 0 : mActiveCueList->RemoveAll();
202 : }
203 :
204 0 : double playbackTime = mediaElement->CurrentTime();
205 : // Remove all the cues from the active cue list whose end times now occur
206 : // earlier then the current playback time.
207 0 : for (uint32_t i = mActiveCueList->Length(); i > 0; i--) {
208 0 : if ((*mActiveCueList)[i - 1]->EndTime() <= playbackTime) {
209 0 : mActiveCueList->RemoveCueAt(i - 1);
210 : }
211 : }
212 : // Add all the cues, starting from the position of the last cue that was
213 : // added, that have valid start and end times for the current playback time.
214 : // We can stop iterating safely once we encounter a cue that does not have
215 : // a valid start time as the cue list is sorted.
216 0 : for (; mCuePos < mCueList->Length() &&
217 0 : (*mCueList)[mCuePos]->StartTime() <= playbackTime; mCuePos++) {
218 0 : if ((*mCueList)[mCuePos]->EndTime() > playbackTime) {
219 0 : mActiveCueList->AddCue(*(*mCueList)[mCuePos]);
220 : }
221 : }
222 : }
223 :
224 : TextTrackCueList*
225 0 : TextTrack::GetActiveCues() {
226 0 : if (mMode != TextTrackMode::Disabled) {
227 0 : return mActiveCueList;
228 : }
229 0 : return nullptr;
230 : }
231 :
232 : void
233 0 : TextTrack::GetActiveCueArray(nsTArray<RefPtr<TextTrackCue> >& aCues)
234 : {
235 0 : if (mMode != TextTrackMode::Disabled) {
236 0 : mActiveCueList->GetArray(aCues);
237 : }
238 0 : }
239 :
240 : TextTrackReadyState
241 0 : TextTrack::ReadyState() const
242 : {
243 0 : return mReadyState;
244 : }
245 :
246 : void
247 0 : TextTrack::SetReadyState(uint32_t aReadyState)
248 : {
249 0 : if (aReadyState <= TextTrackReadyState::FailedToLoad) {
250 0 : SetReadyState(static_cast<TextTrackReadyState>(aReadyState));
251 : }
252 0 : }
253 :
254 : void
255 0 : TextTrack::SetReadyState(TextTrackReadyState aState)
256 : {
257 0 : mReadyState = aState;
258 :
259 0 : if (!mTextTrackList) {
260 0 : return;
261 : }
262 :
263 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
264 0 : if (mediaElement && (mReadyState == TextTrackReadyState::Loaded||
265 0 : mReadyState == TextTrackReadyState::FailedToLoad)) {
266 0 : mediaElement->RemoveTextTrack(this, true);
267 0 : mediaElement->UpdateReadyState();
268 : }
269 : }
270 :
271 : TextTrackList*
272 0 : TextTrack::GetTextTrackList()
273 : {
274 0 : return mTextTrackList;
275 : }
276 :
277 : void
278 0 : TextTrack::SetTextTrackList(TextTrackList* aTextTrackList)
279 : {
280 0 : mTextTrackList = aTextTrackList;
281 0 : }
282 :
283 : HTMLTrackElement*
284 0 : TextTrack::GetTrackElement() {
285 0 : return mTrackElement;
286 : }
287 :
288 : void
289 0 : TextTrack::SetTrackElement(HTMLTrackElement* aTrackElement) {
290 0 : mTrackElement = aTrackElement;
291 0 : }
292 :
293 : void
294 0 : TextTrack::SetCuesInactive()
295 : {
296 0 : mCueList->SetCuesInactive();
297 0 : }
298 :
299 : void
300 0 : TextTrack::NotifyCueUpdated(TextTrackCue *aCue)
301 : {
302 0 : mCueList->NotifyCueUpdated(aCue);
303 0 : if (mTextTrackList) {
304 0 : HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
305 0 : if (mediaElement) {
306 0 : mediaElement->NotifyCueUpdated(aCue);
307 : }
308 : }
309 0 : SetDirty();
310 0 : }
311 :
312 : void
313 0 : TextTrack::GetLabel(nsAString& aLabel) const
314 : {
315 0 : if (mTrackElement) {
316 0 : mTrackElement->GetLabel(aLabel);
317 : } else {
318 0 : aLabel = mLabel;
319 : }
320 0 : }
321 : void
322 0 : TextTrack::GetLanguage(nsAString& aLanguage) const
323 : {
324 0 : if (mTrackElement) {
325 0 : mTrackElement->GetSrclang(aLanguage);
326 : } else {
327 0 : aLanguage = mLanguage;
328 : }
329 0 : }
330 :
331 : void
332 0 : TextTrack::DispatchAsyncTrustedEvent(const nsString& aEventName)
333 : {
334 0 : nsPIDOMWindowInner* win = GetOwner();
335 0 : if (!win) {
336 0 : return;
337 : }
338 0 : RefPtr<TextTrack> self = this;
339 0 : nsGlobalWindow::Cast(win)->Dispatch(
340 : "TextTrack::DispatchAsyncTrustedEvent",
341 : TaskCategory::Other,
342 0 : NS_NewRunnableFunction(
343 : "dom::TextTrack::DispatchAsyncTrustedEvent",
344 0 : [self, aEventName]() { self->DispatchTrustedEvent(aEventName); }));
345 : }
346 :
347 : bool
348 0 : TextTrack::IsLoaded()
349 : {
350 0 : if (mMode == TextTrackMode::Disabled) {
351 0 : return true;
352 : }
353 : // If the TrackElement's src is null, we can not block the
354 : // MediaElement.
355 0 : if (mTrackElement) {
356 0 : nsAutoString src;
357 0 : if (!(mTrackElement->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src))) {
358 0 : return true;
359 : }
360 : }
361 0 : return (mReadyState >= Loaded);
362 : }
363 :
364 : } // namespace dom
365 : } // namespace mozilla
|