| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/html/track/CueTimeline.h" | 5 #include "core/html/track/CueTimeline.h" |
| 6 | 6 |
| 7 #include "core/events/Event.h" | 7 #include "core/events/Event.h" |
| 8 #include "core/html/HTMLMediaElement.h" | 8 #include "core/html/HTMLMediaElement.h" |
| 9 #include "core/html/HTMLTrackElement.h" | 9 #include "core/html/HTMLTrackElement.h" |
| 10 #include "core/html/track/LoadableTextTrack.h" | 10 #include "core/html/track/LoadableTextTrack.h" |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 // has not fired a timeupdate event at the element in the past 15 to 250ms | 182 // has not fired a timeupdate event at the element in the past 15 to 250ms |
| 183 // and is not still running event handlers for such an event, then the user | 183 // and is not still running event handlers for such an event, then the user |
| 184 // agent must queue a task to fire a simple event named timeupdate at the | 184 // agent must queue a task to fire a simple event named timeupdate at the |
| 185 // element. (In the other cases, such as explicit seeks, relevant events get | 185 // element. (In the other cases, such as explicit seeks, relevant events get |
| 186 // fired as part of the overall process of changing the current playback | 186 // fired as part of the overall process of changing the current playback |
| 187 // position.) | 187 // position.) |
| 188 if (!mediaElement.seeking() && lastSeekTime < lastTime) | 188 if (!mediaElement.seeking() && lastSeekTime < lastTime) |
| 189 mediaElement.scheduleTimeupdateEvent(true); | 189 mediaElement.scheduleTimeupdateEvent(true); |
| 190 | 190 |
| 191 // Explicitly cache vector sizes, as their content is constant from here. | 191 // Explicitly cache vector sizes, as their content is constant from here. |
| 192 size_t currentCuesSize = currentCues.size(); | |
| 193 size_t missedCuesSize = missedCues.size(); | 192 size_t missedCuesSize = missedCues.size(); |
| 194 size_t previousCuesSize = previousCues.size(); | 193 size_t previousCuesSize = previousCues.size(); |
| 195 | 194 |
| 196 // 6 - If all of the cues in current cues have their text track cue active | 195 // 6 - If all of the cues in current cues have their text track cue active |
| 197 // flag set, none of the cues in other cues have their text track cue active | 196 // flag set, none of the cues in other cues have their text track cue active |
| 198 // flag set, and missed cues is empty, then abort these steps. | 197 // flag set, and missed cues is empty, then abort these steps. |
| 199 bool activeSetChanged = missedCuesSize; | 198 bool activeSetChanged = missedCuesSize; |
| 200 | 199 |
| 201 for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i) { | 200 for (size_t i = 0; !activeSetChanged && i < previousCuesSize; ++i) { |
| 202 if (!currentCues.contains(previousCues[i]) && | 201 if (!currentCues.contains(previousCues[i]) && |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 235 } |
| 237 | 236 |
| 238 // 8 - Let events be a list of tasks, initially empty. Each task in this | 237 // 8 - Let events be a list of tasks, initially empty. Each task in this |
| 239 // list will be associated with a text track, a text track cue, and a time, | 238 // list will be associated with a text track, a text track cue, and a time, |
| 240 // which are used to sort the list before the tasks are queued. | 239 // which are used to sort the list before the tasks are queued. |
| 241 HeapVector<std::pair<double, Member<TextTrackCue>>> eventTasks; | 240 HeapVector<std::pair<double, Member<TextTrackCue>>> eventTasks; |
| 242 | 241 |
| 243 // 8 - Let affected tracks be a list of text tracks, initially empty. | 242 // 8 - Let affected tracks be a list of text tracks, initially empty. |
| 244 HeapVector<Member<TextTrack>> affectedTracks; | 243 HeapVector<Member<TextTrack>> affectedTracks; |
| 245 | 244 |
| 246 for (size_t i = 0; i < missedCuesSize; ++i) { | 245 for (const auto& missedCue : missedCues) { |
| 247 // 9 - For each text track cue in missed cues, prepare an event named enter | 246 // 9 - For each text track cue in missed cues, prepare an event named enter |
| 248 // for the TextTrackCue object with the text track cue start time. | 247 // for the TextTrackCue object with the text track cue start time. |
| 249 eventTasks.append(std::make_pair(missedCues[i].data()->startTime(), | 248 eventTasks.append( |
| 250 missedCues[i].data())); | 249 std::make_pair(missedCue.data()->startTime(), missedCue.data())); |
| 251 | 250 |
| 252 // 10 - For each text track [...] in missed cues, prepare an event | 251 // 10 - For each text track [...] in missed cues, prepare an event |
| 253 // named exit for the TextTrackCue object with the with the later of | 252 // named exit for the TextTrackCue object with the with the later of |
| 254 // the text track cue end time and the text track cue start time. | 253 // the text track cue end time and the text track cue start time. |
| 255 | 254 |
| 256 // Note: An explicit task is added only if the cue is NOT a zero or | 255 // Note: An explicit task is added only if the cue is NOT a zero or |
| 257 // negative length cue. Otherwise, the need for an exit event is | 256 // negative length cue. Otherwise, the need for an exit event is |
| 258 // checked when these tasks are actually queued below. This doesn't | 257 // checked when these tasks are actually queued below. This doesn't |
| 259 // affect sorting events before dispatch either, because the exit | 258 // affect sorting events before dispatch either, because the exit |
| 260 // event has the same time as the enter event. | 259 // event has the same time as the enter event. |
| 261 if (missedCues[i].data()->startTime() < missedCues[i].data()->endTime()) | 260 if (missedCue.data()->startTime() < missedCue.data()->endTime()) { |
| 262 eventTasks.append(std::make_pair(missedCues[i].data()->endTime(), | 261 eventTasks.append( |
| 263 missedCues[i].data())); | 262 std::make_pair(missedCue.data()->endTime(), missedCue.data())); |
| 263 } |
| 264 } | 264 } |
| 265 | 265 |
| 266 for (size_t i = 0; i < previousCuesSize; ++i) { | 266 for (const auto& previousCue : previousCues) { |
| 267 // 10 - For each text track cue in other cues that has its text | 267 // 10 - For each text track cue in other cues that has its text |
| 268 // track cue active flag set prepare an event named exit for the | 268 // track cue active flag set prepare an event named exit for the |
| 269 // TextTrackCue object with the text track cue end time. | 269 // TextTrackCue object with the text track cue end time. |
| 270 if (!currentCues.contains(previousCues[i])) | 270 if (!currentCues.contains(previousCue)) { |
| 271 eventTasks.append(std::make_pair(previousCues[i].data()->endTime(), | 271 eventTasks.append( |
| 272 previousCues[i].data())); | 272 std::make_pair(previousCue.data()->endTime(), previousCue.data())); |
| 273 } |
| 273 } | 274 } |
| 274 | 275 |
| 275 for (size_t i = 0; i < currentCuesSize; ++i) { | 276 for (const auto& currentCue : currentCues) { |
| 276 // 11 - For each text track cue in current cues that does not have its | 277 // 11 - For each text track cue in current cues that does not have its |
| 277 // text track cue active flag set, prepare an event named enter for the | 278 // text track cue active flag set, prepare an event named enter for the |
| 278 // TextTrackCue object with the text track cue start time. | 279 // TextTrackCue object with the text track cue start time. |
| 279 if (!previousCues.contains(currentCues[i])) | 280 if (!previousCues.contains(currentCue)) { |
| 280 eventTasks.append(std::make_pair(currentCues[i].data()->startTime(), | 281 eventTasks.append( |
| 281 currentCues[i].data())); | 282 std::make_pair(currentCue.data()->startTime(), currentCue.data())); |
| 283 } |
| 282 } | 284 } |
| 283 | 285 |
| 284 // 12 - Sort the tasks in events in ascending time order (tasks with earlier | 286 // 12 - Sort the tasks in events in ascending time order (tasks with earlier |
| 285 // times first). | 287 // times first). |
| 286 nonCopyingSort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare); | 288 nonCopyingSort(eventTasks.begin(), eventTasks.end(), eventTimeCueCompare); |
| 287 | 289 |
| 288 for (size_t i = 0; i < eventTasks.size(); ++i) { | 290 for (const auto& task : eventTasks) { |
| 289 if (!affectedTracks.contains(eventTasks[i].second->track())) | 291 if (!affectedTracks.contains(task.second->track())) |
| 290 affectedTracks.append(eventTasks[i].second->track()); | 292 affectedTracks.append(task.second->track()); |
| 291 | 293 |
| 292 // 13 - Queue each task in events, in list order. | 294 // 13 - Queue each task in events, in list order. |
| 293 | 295 |
| 294 // Each event in eventTasks may be either an enterEvent or an exitEvent, | 296 // Each event in eventTasks may be either an enterEvent or an exitEvent, |
| 295 // depending on the time that is associated with the event. This | 297 // depending on the time that is associated with the event. This |
| 296 // correctly identifies the type of the event, if the startTime is | 298 // correctly identifies the type of the event, if the startTime is |
| 297 // less than the endTime in the cue. | 299 // less than the endTime in the cue. |
| 298 if (eventTasks[i].second->startTime() >= eventTasks[i].second->endTime()) { | 300 if (task.second->startTime() >= task.second->endTime()) { |
| 299 mediaElement.scheduleEvent(createEventWithTarget( | 301 mediaElement.scheduleEvent( |
| 300 EventTypeNames::enter, eventTasks[i].second.get())); | 302 createEventWithTarget(EventTypeNames::enter, task.second.get())); |
| 301 mediaElement.scheduleEvent(createEventWithTarget( | 303 mediaElement.scheduleEvent( |
| 302 EventTypeNames::exit, eventTasks[i].second.get())); | 304 createEventWithTarget(EventTypeNames::exit, task.second.get())); |
| 303 } else { | 305 } else { |
| 304 bool isEnterEvent = | 306 bool isEnterEvent = task.first == task.second->startTime(); |
| 305 eventTasks[i].first == eventTasks[i].second->startTime(); | |
| 306 AtomicString eventName = | 307 AtomicString eventName = |
| 307 isEnterEvent ? EventTypeNames::enter : EventTypeNames::exit; | 308 isEnterEvent ? EventTypeNames::enter : EventTypeNames::exit; |
| 308 mediaElement.scheduleEvent( | 309 mediaElement.scheduleEvent( |
| 309 createEventWithTarget(eventName, eventTasks[i].second.get())); | 310 createEventWithTarget(eventName, task.second.get())); |
| 310 } | 311 } |
| 311 } | 312 } |
| 312 | 313 |
| 313 // 14 - Sort affected tracks in the same order as the text tracks appear in | 314 // 14 - Sort affected tracks in the same order as the text tracks appear in |
| 314 // the media element's list of text tracks, and remove duplicates. | 315 // the media element's list of text tracks, and remove duplicates. |
| 315 nonCopyingSort(affectedTracks.begin(), affectedTracks.end(), | 316 nonCopyingSort(affectedTracks.begin(), affectedTracks.end(), |
| 316 trackIndexCompare); | 317 trackIndexCompare); |
| 317 | 318 |
| 318 // 15 - For each text track in affected tracks, in the list order, queue a | 319 // 15 - For each text track in affected tracks, in the list order, queue a |
| 319 // task to fire a simple event named cuechange at the TextTrack object, and, | 320 // task to fire a simple event named cuechange at the TextTrack object, and, |
| 320 // ... | 321 // ... |
| 321 for (size_t i = 0; i < affectedTracks.size(); ++i) { | 322 for (const auto& track : affectedTracks) { |
| 322 mediaElement.scheduleEvent(createEventWithTarget(EventTypeNames::cuechange, | 323 mediaElement.scheduleEvent( |
| 323 affectedTracks[i].get())); | 324 createEventWithTarget(EventTypeNames::cuechange, track.get())); |
| 324 | 325 |
| 325 // ... if the text track has a corresponding track element, to then fire a | 326 // ... if the text track has a corresponding track element, to then fire a |
| 326 // simple event named cuechange at the track element as well. | 327 // simple event named cuechange at the track element as well. |
| 327 if (affectedTracks[i]->trackType() == TextTrack::TrackElement) { | 328 if (track->trackType() == TextTrack::TrackElement) { |
| 328 HTMLTrackElement* trackElement = | 329 HTMLTrackElement* trackElement = |
| 329 static_cast<LoadableTextTrack*>(affectedTracks[i].get()) | 330 static_cast<LoadableTextTrack*>(track.get())->trackElement(); |
| 330 ->trackElement(); | |
| 331 DCHECK(trackElement); | 331 DCHECK(trackElement); |
| 332 mediaElement.scheduleEvent( | 332 mediaElement.scheduleEvent( |
| 333 createEventWithTarget(EventTypeNames::cuechange, trackElement)); | 333 createEventWithTarget(EventTypeNames::cuechange, trackElement)); |
| 334 } | 334 } |
| 335 } | 335 } |
| 336 | 336 |
| 337 // 16 - Set the text track cue active flag of all the cues in the current | 337 // 16 - Set the text track cue active flag of all the cues in the current |
| 338 // cues, and unset the text track cue active flag of all the cues in the | 338 // cues, and unset the text track cue active flag of all the cues in the |
| 339 // other cues. | 339 // other cues. |
| 340 for (size_t i = 0; i < currentCuesSize; ++i) | 340 for (const auto& cue : currentCues) |
| 341 currentCues[i].data()->setIsActive(true); | 341 cue.data()->setIsActive(true); |
| 342 | 342 |
| 343 for (size_t i = 0; i < previousCuesSize; ++i) { | 343 for (const auto& previousCue : previousCues) { |
| 344 if (!currentCues.contains(previousCues[i])) { | 344 if (!currentCues.contains(previousCue)) { |
| 345 TextTrackCue* cue = previousCues[i].data(); | 345 TextTrackCue* cue = previousCue.data(); |
| 346 cue->setIsActive(false); | 346 cue->setIsActive(false); |
| 347 cue->removeDisplayTree(); | 347 cue->removeDisplayTree(); |
| 348 } | 348 } |
| 349 } | 349 } |
| 350 | 350 |
| 351 // Update the current active cues. | 351 // Update the current active cues. |
| 352 m_currentlyActiveCues = currentCues; | 352 m_currentlyActiveCues = currentCues; |
| 353 mediaElement.updateTextTrackDisplay(); | 353 mediaElement.updateTextTrackDisplay(); |
| 354 } | 354 } |
| 355 | 355 |
| 356 void CueTimeline::beginIgnoringUpdateRequests() { | 356 void CueTimeline::beginIgnoringUpdateRequests() { |
| 357 ++m_ignoreUpdate; | 357 ++m_ignoreUpdate; |
| 358 } | 358 } |
| 359 | 359 |
| 360 void CueTimeline::endIgnoringUpdateRequests() { | 360 void CueTimeline::endIgnoringUpdateRequests() { |
| 361 DCHECK(m_ignoreUpdate); | 361 DCHECK(m_ignoreUpdate); |
| 362 --m_ignoreUpdate; | 362 --m_ignoreUpdate; |
| 363 if (!m_ignoreUpdate) | 363 if (!m_ignoreUpdate) |
| 364 updateActiveCues(mediaElement().currentTime()); | 364 updateActiveCues(mediaElement().currentTime()); |
| 365 } | 365 } |
| 366 | 366 |
| 367 DEFINE_TRACE(CueTimeline) { | 367 DEFINE_TRACE(CueTimeline) { |
| 368 visitor->trace(m_mediaElement); | 368 visitor->trace(m_mediaElement); |
| 369 } | 369 } |
| 370 | 370 |
| 371 } // namespace blink | 371 } // namespace blink |
| OLD | NEW |