Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/TextTrack.cpp
Line
Count
Source (jump to first uncovered line)
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
NS_IMPL_CYCLE_COLLECTION_INHERITED(TextTrack,
22
                                   DOMEventTargetHelper,
23
                                   mCueList,
24
                                   mActiveCueList,
25
                                   mTextTrackList,
26
                                   mTrackElement)
27
28
NS_IMPL_ADDREF_INHERITED(TextTrack, DOMEventTargetHelper)
29
NS_IMPL_RELEASE_INHERITED(TextTrack, DOMEventTargetHelper)
30
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrack)
31
0
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
32
33
TextTrack::TextTrack(nsPIDOMWindowInner* aOwnerWindow,
34
                     TextTrackKind aKind,
35
                     const nsAString& aLabel,
36
                     const nsAString& aLanguage,
37
                     TextTrackMode aMode,
38
                     TextTrackReadyState aReadyState,
39
                     TextTrackSource aTextTrackSource)
40
  : DOMEventTargetHelper(aOwnerWindow)
41
  , mKind(aKind)
42
  , mLabel(aLabel)
43
  , mLanguage(aLanguage)
44
  , mMode(aMode)
45
  , mReadyState(aReadyState)
46
  , mTextTrackSource(aTextTrackSource)
47
0
{
48
0
  SetDefaultSettings();
49
0
}
50
51
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
                     TextTrackSource aTextTrackSource)
59
  : DOMEventTargetHelper(aOwnerWindow)
60
  , mTextTrackList(aTextTrackList)
61
  , mKind(aKind)
62
  , mLabel(aLabel)
63
  , mLanguage(aLanguage)
64
  , mMode(aMode)
65
  , mReadyState(aReadyState)
66
  , mTextTrackSource(aTextTrackSource)
67
0
{
68
0
  SetDefaultSettings();
69
0
}
70
71
TextTrack::~TextTrack()
72
0
{
73
0
}
74
75
void
76
TextTrack::SetDefaultSettings()
77
0
{
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
TextTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
87
0
{
88
0
  return TextTrack_Binding::Wrap(aCx, this, aGivenProto);
89
0
}
90
91
void
92
TextTrack::SetMode(TextTrackMode aValue)
93
0
{
94
0
  if (mMode != aValue) {
95
0
    mMode = aValue;
96
0
    if (aValue == TextTrackMode::Disabled) {
97
0
      // 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
0
          }
104
0
        }
105
0
      }
106
0
      SetCuesInactive();
107
0
    } else {
108
0
      // 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
0
          }
115
0
        }
116
0
      }
117
0
    }
118
0
    if (mTextTrackList) {
119
0
      mTextTrackList->CreateAndDispatchChangeEvent();
120
0
    }
121
0
    // Ensure the TimeMarchesOn is called in case that the mCueList
122
0
    // is empty.
123
0
    NotifyCueUpdated(nullptr);
124
0
  }
125
0
}
126
127
void
128
TextTrack::GetId(nsAString& aId) const
129
0
{
130
0
  // If the track has a track element then its id should be the same as the
131
0
  // track element's id.
132
0
  if (mTrackElement) {
133
0
    mTrackElement->GetAttribute(NS_LITERAL_STRING("id"), aId);
134
0
  }
135
0
}
136
137
void
138
TextTrack::AddCue(TextTrackCue& aCue)
139
0
{
140
0
  TextTrack* oldTextTrack = aCue.GetTrack();
141
0
  if (oldTextTrack) {
142
0
    ErrorResult dummy;
143
0
    oldTextTrack->RemoveCue(aCue, dummy);
144
0
  }
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
0
    }
152
0
  }
153
0
  SetDirty();
154
0
}
155
156
void
157
TextTrack::RemoveCue(TextTrackCue& aCue, ErrorResult& aRv)
158
0
{
159
0
  // Bug1304948, check the aCue belongs to the TextTrack.
160
0
  mCueList->RemoveCue(aCue, aRv);
161
0
  if (aRv.Failed()) {
162
0
    return;
163
0
  }
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
0
    }
171
0
  }
172
0
  SetDirty();
173
0
}
174
175
void
176
TextTrack::SetCuesDirty()
177
0
{
178
0
  for (uint32_t i = 0; i < mCueList->Length(); i++) {
179
0
    ((*mCueList)[i])->Reset();
180
0
  }
181
0
}
182
183
void
184
TextTrack::UpdateActiveCueList()
185
0
{
186
0
  if (!mTextTrackList) {
187
0
    return;
188
0
  }
189
0
190
0
  HTMLMediaElement* mediaElement = mTextTrackList->GetMediaElement();
191
0
  if (!mediaElement) {
192
0
    return;
193
0
  }
194
0
195
0
  // If we are dirty, i.e. an event happened that may cause the sorted mCueList
196
0
  // to have changed like a seek or an insert for a cue, than we need to rebuild
197
0
  // the active cue list from scratch.
198
0
  if (mDirty) {
199
0
    mCuePos = 0;
200
0
    mDirty = false;
201
0
    mActiveCueList->RemoveAll();
202
0
  }
203
0
204
0
  double playbackTime = mediaElement->CurrentTime();
205
0
  // Remove all the cues from the active cue list whose end times now occur
206
0
  // 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
0
    }
211
0
  }
212
0
  // Add all the cues, starting from the position of the last cue that was
213
0
  // added, that have valid start and end times for the current playback time.
214
0
  // We can stop iterating safely once we encounter a cue that does not have
215
0
  // 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
0
    }
221
0
  }
222
0
}
223
224
TextTrackCueList*
225
0
TextTrack::GetActiveCues() {
226
0
  if (mMode != TextTrackMode::Disabled) {
227
0
    return mActiveCueList;
228
0
  }
229
0
  return nullptr;
230
0
}
231
232
void
233
TextTrack::GetActiveCueArray(nsTArray<RefPtr<TextTrackCue> >& aCues)
234
0
{
235
0
  if (mMode != TextTrackMode::Disabled) {
236
0
    mActiveCueList->GetArray(aCues);
237
0
  }
238
0
}
239
240
TextTrackReadyState
241
TextTrack::ReadyState() const
242
0
{
243
0
  return mReadyState;
244
0
}
245
246
void
247
TextTrack::SetReadyState(uint32_t aReadyState)
248
0
{
249
0
  if (aReadyState <= TextTrackReadyState::FailedToLoad) {
250
0
    SetReadyState(static_cast<TextTrackReadyState>(aReadyState));
251
0
  }
252
0
}
253
254
void
255
TextTrack::SetReadyState(TextTrackReadyState aState)
256
0
{
257
0
  mReadyState = aState;
258
0
259
0
  if (!mTextTrackList) {
260
0
    return;
261
0
  }
262
0
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
0
  }
269
0
}
270
271
TextTrackList*
272
TextTrack::GetTextTrackList()
273
0
{
274
0
  return mTextTrackList;
275
0
}
276
277
void
278
TextTrack::SetTextTrackList(TextTrackList* aTextTrackList)
279
0
{
280
0
  mTextTrackList = aTextTrackList;
281
0
}
282
283
HTMLTrackElement*
284
0
TextTrack::GetTrackElement() {
285
0
  return mTrackElement;
286
0
}
287
288
void
289
0
TextTrack::SetTrackElement(HTMLTrackElement* aTrackElement) {
290
0
  mTrackElement = aTrackElement;
291
0
}
292
293
void
294
TextTrack::SetCuesInactive()
295
0
{
296
0
  mCueList->SetCuesInactive();
297
0
}
298
299
void
300
TextTrack::NotifyCueUpdated(TextTrackCue *aCue)
301
0
{
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
0
    }
308
0
  }
309
0
  SetDirty();
310
0
}
311
312
void
313
TextTrack::GetLabel(nsAString& aLabel) const
314
0
{
315
0
  if (mTrackElement) {
316
0
    mTrackElement->GetLabel(aLabel);
317
0
  } else {
318
0
    aLabel = mLabel;
319
0
  }
320
0
}
321
void
322
TextTrack::GetLanguage(nsAString& aLanguage) const
323
0
{
324
0
  if (mTrackElement) {
325
0
    mTrackElement->GetSrclang(aLanguage);
326
0
  } else {
327
0
    aLanguage = mLanguage;
328
0
  }
329
0
}
330
331
void
332
TextTrack::DispatchAsyncTrustedEvent(const nsString& aEventName)
333
0
{
334
0
  nsPIDOMWindowInner* win = GetOwner();
335
0
  if (!win) {
336
0
    return;
337
0
  }
338
0
  RefPtr<TextTrack> self = this;
339
0
  nsGlobalWindowInner::Cast(win)->Dispatch(
340
0
    TaskCategory::Other,
341
0
    NS_NewRunnableFunction(
342
0
      "dom::TextTrack::DispatchAsyncTrustedEvent",
343
0
      [self, aEventName]() { self->DispatchTrustedEvent(aEventName); }));
344
0
}
345
346
bool
347
TextTrack::IsLoaded()
348
0
{
349
0
  if (mMode == TextTrackMode::Disabled) {
350
0
    return true;
351
0
  }
352
0
  // If the TrackElement's src is null, we can not block the
353
0
  // MediaElement.
354
0
  if (mTrackElement) {
355
0
    nsAutoString src;
356
0
    if (!(mTrackElement->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src))) {
357
0
      return true;
358
0
    }
359
0
  }
360
0
  return (mReadyState >= Loaded);
361
0
}
362
363
} // namespace dom
364
} // namespace mozilla