2013-06-25 06:23:00 +04:00
|
|
|
<!DOCTYPE HTML>
|
|
|
|
<html>
|
|
|
|
<head>
|
|
|
|
<title>Test for Bug 833386 - HTMLTrackElement</title>
|
2019-04-16 06:53:28 +03:00
|
|
|
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
2019-05-24 03:41:04 +03:00
|
|
|
<script type="text/javascript" src="manifest.js"></script>
|
2013-06-25 06:23:00 +04:00
|
|
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
|
|
|
</head>
|
|
|
|
<body>
|
2019-05-24 03:41:08 +03:00
|
|
|
<video id="v" src="seek.webm" preload="metadata">
|
|
|
|
<track src="basic.vtt" kind="subtitles" id="default" default>
|
|
|
|
</video>
|
2019-05-24 03:41:12 +03:00
|
|
|
<script type="text/javascript">
|
2019-05-24 03:41:02 +03:00
|
|
|
/**
|
|
|
|
* This test is used to test the VTTCue's different behaviors and check whether
|
|
|
|
* cues would be activatived correctly during video playback.
|
|
|
|
*/
|
2019-05-24 03:41:04 +03:00
|
|
|
var video = document.getElementById("v");
|
|
|
|
var trackElement = document.getElementById("default");
|
|
|
|
|
|
|
|
async function runTest() {
|
|
|
|
await waitUntiTrackLoaded();
|
2019-05-24 03:41:02 +03:00
|
|
|
checkCueDefinition();
|
|
|
|
checkFirstCueParsedContent();
|
|
|
|
checkCueStartTimeAndEndtime();
|
|
|
|
checkCueSizeAndPosition();
|
|
|
|
checkCueSnapToLines();
|
|
|
|
checkCueAlignmentAndWritingDirection();
|
|
|
|
checkCueLine();
|
|
|
|
checkCreatingNewCue();
|
|
|
|
checkRemoveNonExistCue();
|
|
|
|
checkActiveCues();
|
|
|
|
checkCueRegion();
|
|
|
|
await checkCActiveCuesDuringVideoPlaying();
|
|
|
|
SimpleTest.finish();
|
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
SimpleTest.waitForExplicitFinish();
|
|
|
|
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.regions.enabled", true]]},
|
|
|
|
runTest);
|
|
|
|
/**
|
|
|
|
* The following are test helper functions.
|
|
|
|
*/
|
|
|
|
async function waitUntiTrackLoaded() {
|
|
|
|
if (trackElement.readyState != 2) {
|
|
|
|
info(`wait until the track finishes loading`);
|
|
|
|
await once(trackElement, "load");
|
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
is(trackElement.readyState, 2, "Track::ReadyState should be set to LOADED.");
|
2019-05-24 03:41:02 +03:00
|
|
|
is(trackElement.track.cues.length, 6, "Cue list length should be 6.");
|
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueDefinition() {
|
2019-05-24 03:41:04 +03:00
|
|
|
// Check that the typedef of TextTrackCue works in Gecko.
|
|
|
|
isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined.");
|
|
|
|
isnot(window.VTTCue, undefined, "VTTCue should be defined.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkFirstCueParsedContent() {
|
2019-05-24 03:41:04 +03:00
|
|
|
// Check if first cue was parsed correctly.
|
2019-05-24 03:41:02 +03:00
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
ok(cue instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue.");
|
|
|
|
ok(cue instanceof VTTCue, "Cue should be an instanceof VTTCue.");
|
|
|
|
is(cue.id, "1", "Cue's ID should be 1.");
|
|
|
|
is(cue.startTime, 0.5, "Cue's start time should be 0.5.");
|
|
|
|
is(cue.endTime, 0.7, "Cue's end time should be 0.7.");
|
|
|
|
is(cue.pauseOnExit, false, "Cue's pause on exit flag should be false.");
|
|
|
|
is(cue.text, "This", "Cue's text should be set correctly.");
|
|
|
|
is(cue.track, trackElement.track, "Cue's track should be defined.");
|
|
|
|
cue.track = null;
|
|
|
|
isnot(cue.track, null, "Cue's track should not be able to be set.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueStartTimeAndEndtime() {
|
|
|
|
const cueList = trackElement.track.cues;
|
2019-05-24 03:41:04 +03:00
|
|
|
// Check that all cue times were not rounded
|
|
|
|
is(cueList[1].startTime, 1.2, "Second cue's start time should be 1.2.");
|
|
|
|
is(cueList[1].endTime, 2.4, "Second cue's end time should be 2.4.");
|
|
|
|
is(cueList[2].startTime, 2, "Third cue's start time should be 2.");
|
|
|
|
is(cueList[2].endTime, 3.5, "Third cue's end time should be 3.5.");
|
|
|
|
is(cueList[3].startTime, 2.71, "Fourth cue's start time should be 2.71.");
|
|
|
|
is(cueList[3].endTime, 2.91, "Fourth cue's end time should be 2.91.");
|
|
|
|
is(cueList[4].startTime, 3.217, "Fifth cue's start time should be 3.217.");
|
|
|
|
is(cueList[4].endTime, 3.989, "Fifth cue's end time should be 3.989.");
|
|
|
|
is(cueList[5].startTime, 3.217, "Sixth cue's start time should be 3.217.");
|
|
|
|
is(cueList[5].endTime, 3.989, "Sixth cue's end time should be 3.989.");
|
|
|
|
|
|
|
|
// Check that Cue setters are working correctly.
|
2019-05-24 03:41:02 +03:00
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
cue.id = "Cue 01";
|
|
|
|
is(cue.id, "Cue 01", "Cue's ID should be 'Cue 01'.");
|
|
|
|
cue.startTime = 0.51;
|
|
|
|
is(cue.startTime, 0.51, "Cue's start time should be 0.51.");
|
|
|
|
cue.endTime = 0.71;
|
|
|
|
is(cue.endTime, 0.71, "Cue's end time should be 0.71.");
|
|
|
|
cue.pauseOnExit = true;
|
|
|
|
is(cue.pauseOnExit, true, "Cue's pause on exit flag should be true.");
|
|
|
|
video.addEventListener("pause", function() {
|
|
|
|
video.play();
|
|
|
|
}, {once: true});
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueSizeAndPosition() {
|
2019-05-24 03:41:04 +03:00
|
|
|
function checkPercentageValue(prop, initialVal) {
|
|
|
|
ok(prop in cue, prop + " should be a property on VTTCue.");
|
|
|
|
cue[prop] = initialVal;
|
2019-05-24 03:41:02 +03:00
|
|
|
is(cue[prop], initialVal, `Cue's ${prop} should initially be ${initialVal}`);
|
2019-05-24 03:41:04 +03:00
|
|
|
[ 101, -1 ].forEach(function(val) {
|
2019-10-24 13:50:59 +03:00
|
|
|
let exceptionHappened = false;
|
2019-05-24 03:41:04 +03:00
|
|
|
try {
|
2019-05-24 03:41:06 +03:00
|
|
|
cue[prop] = val;
|
2019-05-24 03:41:04 +03:00
|
|
|
} catch(e) {
|
|
|
|
exceptionHappened = true;
|
|
|
|
is(e.name, "IndexSizeError", "Should have thrown IndexSizeError.");
|
|
|
|
}
|
|
|
|
ok(exceptionHappened, "Exception should have happened.");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
checkPercentageValue("size", 100.0);
|
|
|
|
cue.size = 50.5;
|
|
|
|
is(cue.size, 50.5, "Cue's size should be 50.5.")
|
|
|
|
|
|
|
|
// Check cue.position
|
|
|
|
checkPercentageValue("position", "auto");
|
|
|
|
cue.position = 50.5;
|
|
|
|
is(cue.position, 50.5, "Cue's position value should now be 50.5.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueSnapToLines() {
|
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
ok(cue.snapToLines, "Cue's snapToLines should be set by set.");
|
|
|
|
cue.snapToLines = false;
|
|
|
|
ok(!cue.snapToLines, "Cue's snapToLines should not be set.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueAlignmentAndWritingDirection() {
|
2019-05-24 03:41:04 +03:00
|
|
|
function checkEnumValue(prop, initialVal, acceptedValues) {
|
2019-05-24 03:41:02 +03:00
|
|
|
ok(prop in cue, `${prop} should be a property on VTTCue.`);
|
|
|
|
is(cue[prop], initialVal, `Cue's ${prop} should be ${initialVal}`);
|
2019-05-24 03:41:04 +03:00
|
|
|
cue[prop] = "bogus";
|
2019-05-24 03:41:02 +03:00
|
|
|
is(cue[prop], initialVal, `Cue's ${prop} should be ${initialVal}`);
|
2019-05-24 03:41:04 +03:00
|
|
|
acceptedValues.forEach(function(val) {
|
|
|
|
cue[prop] = val;
|
2019-05-24 03:41:02 +03:00
|
|
|
is(cue[prop], val, `Cue's ${prop} should be ${val}`);
|
2019-05-24 03:41:04 +03:00
|
|
|
if (typeof val === "string") {
|
|
|
|
cue[prop] = val.toUpperCase();
|
2019-05-24 03:41:02 +03:00
|
|
|
is(cue[prop], val, `Cue's ${prop} should be ${val}`);
|
2019-05-23 12:03:16 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
checkEnumValue("align", "center", [ "start", "left", "center", "right", "end" ]);
|
|
|
|
checkEnumValue("lineAlign", "start", [ "start", "center", "end" ]);
|
|
|
|
checkEnumValue("vertical", "", [ "", "lr", "rl" ]);
|
|
|
|
|
|
|
|
cue.lineAlign = "center";
|
|
|
|
is(cue.lineAlign, "center", "Cue's line align should be center.");
|
|
|
|
cue.lineAlign = "START";
|
|
|
|
is(cue.lineAlign, "center", "Cue's line align should be center.");
|
|
|
|
cue.lineAlign = "end";
|
|
|
|
is(cue.lineAlign, "end", "Cue's line align should be end.");
|
|
|
|
|
|
|
|
// Check that cue position align works properly
|
|
|
|
is(cue.positionAlign, "auto", "Cue's default position alignment should be auto.");
|
|
|
|
|
|
|
|
cue.positionAlign = "line-left";
|
|
|
|
is(cue.positionAlign, "line-left", "Cue's position align should be line-left.");
|
|
|
|
cue.positionAlign = "auto";
|
|
|
|
is(cue.positionAlign, "auto", "Cue's position align should be auto.");
|
|
|
|
cue.positionAlign = "line-right";
|
|
|
|
is(cue.positionAlign, "line-right", "Cue's position align should be line-right.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueLine() {
|
|
|
|
const cue = trackElement.track.cues[0];
|
2019-05-24 03:41:04 +03:00
|
|
|
// Check cue.line
|
|
|
|
is(cue.line, "auto", "Cue's line value should initially be auto.");
|
|
|
|
cue.line = 0.5;
|
|
|
|
is(cue.line, 0.5, "Cue's line value should now be 0.5.");
|
|
|
|
cue.line = "auto";
|
|
|
|
is(cue.line, "auto", "Cue's line value should now be auto.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function checkCreatingNewCue() {
|
|
|
|
const cueList = trackElement.track.cues;
|
2019-05-24 03:41:04 +03:00
|
|
|
|
|
|
|
// Check that we can create and add new VTTCues
|
2019-05-24 03:41:02 +03:00
|
|
|
let vttCue = new VTTCue(3.999, 4, "foo");
|
2019-05-24 03:41:04 +03:00
|
|
|
is(vttCue.track, null, "Cue's track should be null.");
|
|
|
|
trackElement.track.addCue(vttCue);
|
2019-05-24 03:41:02 +03:00
|
|
|
is(vttCue.track, trackElement.track, "Cue's track should be defined.");
|
2019-05-24 03:41:04 +03:00
|
|
|
is(cueList.length, 7, "Cue list length should now be 7.");
|
|
|
|
|
|
|
|
// Check that new VTTCue was added correctly
|
2019-05-24 03:41:02 +03:00
|
|
|
let cue = cueList[6];
|
2019-05-24 03:41:04 +03:00
|
|
|
is(cue.startTime, 3.999, "Cue's start time should be 3.999.");
|
|
|
|
is(cue.endTime, 4, "Cue's end time should be 4.");
|
|
|
|
is(cue.text, "foo", "Cue's text should be foo.");
|
|
|
|
|
|
|
|
// Adding the same cue again should not increase the cue count.
|
|
|
|
trackElement.track.addCue(vttCue);
|
|
|
|
is(cueList.length, 7, "Cue list length should be 7.");
|
|
|
|
|
|
|
|
// Check that we are able to remove cues.
|
|
|
|
trackElement.track.removeCue(cue);
|
|
|
|
is(cueList.length, 6, "Cue list length should be 6.");
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkRemoveNonExistCue() {
|
|
|
|
is(trackElement.track.cues.length, 6, "Cue list length should be 6.");
|
|
|
|
let exceptionHappened = false;
|
2019-05-24 03:41:04 +03:00
|
|
|
try {
|
|
|
|
// We should not be able to remove a cue that is not in the list.
|
2019-05-24 03:41:02 +03:00
|
|
|
trackElement.track.removeCue(new VTTCue(1, 2, "foo"));
|
2019-05-24 03:41:04 +03:00
|
|
|
} catch (e) {
|
|
|
|
// "NotFoundError" should be thrown when trying to remove a cue that is
|
|
|
|
// not in the list.
|
|
|
|
is(e.name, "NotFoundError", "Should have thrown NotFoundError.");
|
|
|
|
exceptionHappened = true;
|
|
|
|
}
|
|
|
|
// If this is false then we did not throw an error and probably removed a cue
|
|
|
|
// when we shouln't have.
|
|
|
|
ok(exceptionHappened, "Exception should have happened.");
|
2019-05-24 03:41:02 +03:00
|
|
|
is(trackElement.track.cues.length, 6, "Cue list length should still be 6.");
|
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkActiveCues() {
|
2019-05-24 03:41:04 +03:00
|
|
|
video.currentTime = 2;
|
|
|
|
isnot(trackElement.track.activeCues, null);
|
|
|
|
|
|
|
|
trackElement.track.mode = "disabled";
|
2019-05-24 03:41:02 +03:00
|
|
|
is(trackElement.track.activeCues, null, "No active cue when track is disabled.");
|
2019-05-24 03:41:04 +03:00
|
|
|
trackElement.track.mode = "showing";
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
function checkCueRegion() {
|
|
|
|
let regionInfo = [
|
2019-05-24 03:41:04 +03:00
|
|
|
{ lines: 2, width: 30 },
|
|
|
|
{ lines: 4, width: 20 },
|
|
|
|
{ lines: 2, width: 30 }
|
|
|
|
];
|
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
for (let i = 0; i < regionInfo.length; i++) {
|
|
|
|
let cue = trackElement.track.cues[i];
|
|
|
|
isnot(cue.region, null, `Cue at ${i} should have a region.`);
|
|
|
|
for (let key in regionInfo[i]) {
|
|
|
|
is(cue.region[key], regionInfo[i][key],
|
|
|
|
`Region should have a ${key} property with a value of ${regionInfo[i][key]}`);
|
2019-05-24 03:41:06 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
}
|
2019-05-24 03:41:02 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
async function checkCActiveCuesDuringVideoPlaying() {
|
2019-05-24 03:41:04 +03:00
|
|
|
// Test TextTrack::ActiveCues.
|
2019-05-24 03:41:02 +03:00
|
|
|
let cueInfo = [
|
2019-05-24 03:41:04 +03:00
|
|
|
{ startTime: 0.51, endTime: 0.71, ids: ["Cue 01"] },
|
|
|
|
{ startTime: 0.72, endTime: 1.19, ids: [] },
|
|
|
|
{ startTime: 1.2, endTime: 1.9, ids: [2] },
|
|
|
|
{ startTime: 2, endTime: 2.4, ids: [2, 2.5] },
|
|
|
|
{ startTime: 2.41, endTime: 2.70, ids: [2.5] },
|
|
|
|
{ startTime: 2.71, endTime: 2.91, ids: [2.5, 3] },
|
|
|
|
{ startTime: 2.92, endTime: 3.216, ids: [2.5] },
|
|
|
|
{ startTime: 3.217, endTime: 3.5, ids: [2.5, 4, 5] },
|
|
|
|
{ startTime: 3.51, endTime: 3.989, ids: [4, 5] },
|
|
|
|
{ startTime: 3.99, endTime: 4, ids: [] }
|
|
|
|
];
|
|
|
|
|
|
|
|
video.addEventListener("timeupdate", function() {
|
2019-05-24 03:41:02 +03:00
|
|
|
let activeCues = trackElement.track.activeCues,
|
2019-05-24 03:41:04 +03:00
|
|
|
playbackTime = video.currentTime;
|
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
for (let i = 0; i < cueInfo.length; i++) {
|
|
|
|
let cue = cueInfo[i];
|
2019-05-24 03:41:04 +03:00
|
|
|
if (playbackTime >= cue.startTime && playbackTime < cue.endTime) {
|
2019-05-24 03:41:02 +03:00
|
|
|
is(activeCues.length, cue.ids.length, `There should be ${cue.ids.length} currently active cue(s).`);
|
|
|
|
for (let j = 0; j < cue.ids.length; j++) {
|
|
|
|
isnot(activeCues.getCueById(cue.ids[j]), undefined,
|
|
|
|
`The cue with ID ${cue.ids[j]} should be active.`);
|
2019-05-24 03:38:26 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
break;
|
2019-05-24 03:41:06 +03:00
|
|
|
}
|
2019-05-24 03:41:04 +03:00
|
|
|
}
|
|
|
|
});
|
2019-05-23 12:03:14 +03:00
|
|
|
|
2019-05-24 03:41:02 +03:00
|
|
|
info(`start video from 0s.`);
|
|
|
|
video.currentTime = 0;
|
2019-05-24 03:41:04 +03:00
|
|
|
video.play();
|
2019-05-24 03:41:02 +03:00
|
|
|
await once(video, "playing");
|
|
|
|
info(`video starts playing.`);
|
|
|
|
await once(video, "ended");
|
2019-05-24 03:41:04 +03:00
|
|
|
}
|
|
|
|
|
2013-06-25 06:23:00 +04:00
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
</html>
|