commit 209d8b13d678c5b4bbc2fb0ab85b403d866c50d6
parent cd0bbb31a186272a2595f924c920fbfec79eef03
Author: Syed AbuTalib <lowkey@google.com>
Date: Tue, 21 Oct 2025 10:16:04 +0000
Bug 1994336 [wpt PR 55404] - Handle newly introduced cues in TimeMarchesOn, a=testonly
Automatic update from web-platform-tests
Handle newly introduced cues in TimeMarchesOn
This CL adds a new `newly_introduced_cues_` member to `CueTimeline` to
track cues that are added via `AddCue` or `AddCues`.
As seen in step 5 of the Time Marches On algorithm (
https://html.spec.whatwg.org/multipage/media.html#list-of-newly-introduced-cues
), we must keep track of newly introduced cues and remove the missed
cues that were newly introduced.
This CL prevents `onenter` and `onexit` events from being fired due to
missed cues completely before the current timestamp. The events will
continue to fire if the user seeks to before the cue's startTime.
Bug: 324909835
Change-Id: I28c6be52466e0a90accbe86de9205bce5f429eb1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6997932
Reviewed-by: Philip Jägenstedt <foolip@chromium.org>
Commit-Queue: Syed AbuTalib <lowkey@google.com>
Cr-Commit-Position: refs/heads/main@{#1529839}
--
wpt-commits: b55ba22b0e8e09ba61c7776811a132729c412dad
wpt-pr: 55404
Diffstat:
2 files changed, 100 insertions(+), 0 deletions(-)
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-add-new-track.html b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-add-new-track.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<title>Adding a new track with a cue during playback should fire events</title>
+<script src="/common/media.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video>
+</video>
+<script>
+async_test(t => {
+ const video = document.querySelector("video");
+ let trackAdded = false;
+ let cue1Entered = false;
+ let cue1Exited = false;
+ let cue2Entered = false;
+ let cue2Exited = false;
+
+ // Test Case 1: Track added before video.play()
+ const track1 = video.addTextTrack("subtitles");
+ let cue1 = new VTTCue(0.1, 0.3, "Cue1");
+ cue1.onenter = t.step_func(() => {
+ cue1Entered = true;
+ });
+ cue1.onexit = t.step_func(() => {
+ cue1Exited = true;
+ maybeDone();
+ });
+ track1.addCue(cue1);
+
+ video.ontimeupdate = t.step_func(() => {
+ // Test Case 2: Add a new track after video starts playing.
+ if (!trackAdded && video.currentTime > 0.1) {
+ trackAdded = true;
+ const track2 = video.addTextTrack("subtitles");
+ let cue2 = new VTTCue(video.currentTime + 0.1, video.currentTime + 0.3, "Cue2");
+ cue2.onenter = t.step_func(() => {
+ cue2Entered = true;
+ });
+ cue2.onexit = t.step_func(() => {
+ cue2Exited = true;
+ maybeDone();
+ });
+ track2.addCue(cue2);
+ }
+
+ if (video.currentTime > 1.0) {
+ video.ontimeupdate = null;
+ // Fail the test if not all events have fired by now
+ assert_true(cue1Entered, "Cue1 should have entered");
+ assert_true(cue1Exited, "Cue1 should have exited");
+ assert_true(cue2Entered, "Cue2 should have entered");
+ assert_true(cue2Exited, "Cue2 should have exited");
+ t.done();
+ }
+ });
+
+ function maybeDone() {
+ if (cue1Entered && cue1Exited && cue2Entered && cue2Exited) {
+ video.ontimeupdate = null;
+ t.done();
+ }
+ }
+
+ video.src = getVideoURI("/media/test");
+ video.play();
+});
+</script>
diff --git a/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed-no-immediate-events.html b/testing/web-platform/tests/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed-no-immediate-events.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Adding a missed cue during playback should not fire events</title>
+<script src="/common/media.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video>
+</video>
+<script>
+async_test(t => {
+ const video = document.querySelector("video");
+ const track = video.addTextTrack("subtitles");
+ let cueAdded = false;
+
+ video.ontimeupdate = t.step_func(() => {
+ // After 0.3s, add a cue that is completely before currentTime.
+ if (!cueAdded && video.currentTime > 0.3) {
+ cueAdded = true;
+ let missedCue = new VTTCue(0.1, 0.3, "Test");
+ missedCue.onenter = t.unreached_func("onenter for missed cue should not fire");
+ missedCue.onexit = t.unreached_func("onexit for missed cue should not fire");
+ track.addCue(missedCue);
+ }
+
+ // We should play past 1s without the events firing.
+ if (video.currentTime > 1.0) {
+ video.ontimeupdate = null;
+ t.done();
+ }
+ });
+
+ video.src = getVideoURI("/media/test");
+ video.play();
+});
+</script>