mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-15 16:06:41 +03:00
22a7c497b0
Fix rendering of align:start and align:end in UITextDisplayer Fix rendering of position in UITextDisplayer Fixes https://github.com/shaka-project/shaka-player/issues/4486
519 lines
14 KiB
JavaScript
519 lines
14 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
filterDescribe('WebVTT layout', shaka.test.TextLayoutTests.supported, () => {
|
|
/** @type {shaka.test.TextLayoutTests} */
|
|
let helper;
|
|
|
|
describe('using UI', () => {
|
|
beforeAll(async () => {
|
|
helper = new shaka.test.DomTextLayoutTests('webvtt-ui');
|
|
|
|
await helper.beforeAll();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await helper.beforeEach();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await helper.afterEach();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await helper.afterAll();
|
|
});
|
|
|
|
defineTests();
|
|
});
|
|
|
|
describe('using browser-native rendering', () => {
|
|
beforeAll(async () => {
|
|
helper = new shaka.test.NativeTextLayoutTests('webvtt-native');
|
|
|
|
await helper.beforeAll();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await helper.beforeEach();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await helper.afterEach();
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await helper.afterAll();
|
|
});
|
|
|
|
defineTests();
|
|
});
|
|
|
|
function defineTests() {
|
|
// The initial set of tests here were a subset of the official test suite:
|
|
// https://github.com/web-platform-tests/wpt/tree/master/webvtt/rendering/cues-with-video/processing-model
|
|
|
|
it('align center', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center');
|
|
});
|
|
|
|
// FIXME: UI version is slightly wrong: black background should hug text
|
|
it('align center long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center\n',
|
|
'This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center-long');
|
|
});
|
|
|
|
it('align center position 50%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center position:50%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center-position-50');
|
|
});
|
|
|
|
it('align center position 90%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center position:90%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center-position-90');
|
|
});
|
|
|
|
// FIXME: UI version is wrong: not positioned on the left
|
|
it('align center position 10%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center position:10%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center-position-10');
|
|
});
|
|
|
|
it('align center position 10% size 10%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:center position:10% size:10%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-center-position-10-size-10');
|
|
});
|
|
|
|
it('align end', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:end\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-end');
|
|
});
|
|
|
|
// FIXME: UI version is slightly wrong: black background should hug text
|
|
it('align end long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:end\n',
|
|
'This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-end-long');
|
|
});
|
|
|
|
it('align start', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:start\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-start');
|
|
});
|
|
|
|
// FIXME: UI version is slightly wrong: black background should hug text
|
|
it('align start long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:start\n',
|
|
'This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-start-long');
|
|
});
|
|
|
|
// FIXME: both versions are wrong, top-left corner should be centered
|
|
it('align with position and line', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 ', // continued on next line
|
|
'align:start position:50%,line-left line:50%,start\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('align-position-line');
|
|
});
|
|
|
|
it('size 50%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 size:50%\n',
|
|
'This is a test subtitle that should wrap no matter what\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('size-50');
|
|
});
|
|
|
|
it('line -2', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 line:-2\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('line-negative-2');
|
|
});
|
|
|
|
it('line 0', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 line:0\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('line-0');
|
|
});
|
|
|
|
it('line 1', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 line:1\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('line-1');
|
|
});
|
|
|
|
it('line 50%', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 line:50%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('line-50');
|
|
});
|
|
|
|
// Regression case for http://b/259121343
|
|
// The top center of the cue box should be 85% from the top and
|
|
// horizontally centered.
|
|
// NOTE: The native version is wrong on Chrome and Edge due to layout bugs
|
|
// in Chrome. https://crbug.com/1411464
|
|
it('align to bottom center with restricted size', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 ', // continued on next line
|
|
'line:85% position:50% size:63%\n',
|
|
'This is a test\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('line-85-position-50-size-63');
|
|
});
|
|
|
|
it('bold long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:start\n',
|
|
'<b>This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.</b>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('bold-long');
|
|
});
|
|
|
|
it('italic long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:start\n',
|
|
'<i>This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.</i>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('italic-long');
|
|
});
|
|
|
|
it('underline long', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 align:start\n',
|
|
'<u>This is a test subtitle that most likely will span over several ',
|
|
'rows since it is a pretty long cue with a lot of text.</u>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('underline-long');
|
|
});
|
|
|
|
it('escaped entities', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'Here are the escaped entities: & < > ‎ ‏ \n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('escaped-entities');
|
|
});
|
|
|
|
it('white spaces', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
// eslint-disable-next-line no-tabs
|
|
'A A A A A A\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('white-spaces');
|
|
});
|
|
|
|
it('embedded styles', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'STYLE\n',
|
|
'*|*::cue(b) {\n',
|
|
' background: blue;\n',
|
|
'}\n',
|
|
'|*::cue(i) {\n',
|
|
' color: blue;\n',
|
|
'}\n',
|
|
'::cue(i) {\n',
|
|
' background: white;\n',
|
|
'}\n',
|
|
'*::cue(b) {\n',
|
|
' color: white;\n',
|
|
'}\n',
|
|
'::cue {\n',
|
|
' font-size: 30px;\n',
|
|
'}\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'This <i>is</i> a <b>test</b> subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('embedded-styles');
|
|
});
|
|
|
|
it('voices', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'This is a <v foo>test subtitle</v>, <v bar>test subtitle</v>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('voices');
|
|
});
|
|
|
|
it('voices with styles', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'STYLE\n',
|
|
'::cue(v[voice=foo]) {\n',
|
|
' background: blue;\n',
|
|
'}\n',
|
|
'::cue(v[voice=bar]) {\n',
|
|
' background: red;\n',
|
|
'}\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'This is a <v foo>test subtitle</v>, <v bar>test subtitle</v>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('voices-with-styles');
|
|
});
|
|
|
|
it('classes', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'This is a <c.foo>test subtitle</c>, <c.bar>test subtitle</c>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('classes');
|
|
});
|
|
|
|
it('classes with styles', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'STYLE\n',
|
|
'::cue(.foo) {\n',
|
|
' background: blue;\n',
|
|
'}\n',
|
|
'::cue(.bar) {\n',
|
|
' background: red;\n',
|
|
'}\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000\n',
|
|
'This is a <c.foo>test subtitle</c>, <c.bar>test subtitle</c>\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('classes-with-styles');
|
|
});
|
|
|
|
// FIXME: regions not supported
|
|
it('region without anchors', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'REGION\n',
|
|
'id:1\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a test subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('region-no-anchors');
|
|
});
|
|
|
|
// FIXME: regions not supported
|
|
it('region anchored at top center', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'REGION\n',
|
|
'id:1\n',
|
|
'regionanchor:50%,0%\n',
|
|
'viewportanchor:50%,0%\n',
|
|
'width:100%\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a test subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('region-anchor-top-center');
|
|
});
|
|
|
|
// FIXME: regions not supported
|
|
it('region anchored at top left', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'REGION\n',
|
|
'id:1\n',
|
|
'regionanchor:0%,0%\n',
|
|
'viewportanchor:0%,0%\n',
|
|
'width:100%\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a test subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('region-anchor-top-left');
|
|
});
|
|
|
|
// FIXME: regions not supported
|
|
it('region with complex anchors', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'REGION\n',
|
|
'id:1\n',
|
|
'regionanchor:0%,100%\n',
|
|
'viewportanchor:50%,50%\n',
|
|
'width:30%\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a test subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('region-complex-anchors');
|
|
});
|
|
|
|
// FIXME: regions not supported
|
|
it('region 2 lines scroll up', async () => {
|
|
parseAndDisplay([
|
|
'WEBVTT\n',
|
|
'\n',
|
|
'REGION\n',
|
|
'id:1\n',
|
|
'regionanchor:50%,0%\n',
|
|
'viewportanchor:50%,0%\n',
|
|
'width:100%\n',
|
|
'lines:2\n',
|
|
'scroll:up\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a first test subtitle\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a second test subtitle\n',
|
|
'\n',
|
|
'00:00:00.000 --> 00:00:05.000 region:1\n',
|
|
'This is a third test subtitle\n',
|
|
].join(''));
|
|
|
|
await helper.checkScreenshot('region-2-lines-scroll-up');
|
|
});
|
|
}
|
|
|
|
/** @param {string} text */
|
|
function parseAndDisplay(text) {
|
|
const data =
|
|
shaka.util.BufferUtils.toUint8(shaka.util.StringUtils.toUTF8(text));
|
|
const time = {
|
|
periodStart: 0,
|
|
segmentStart: 0,
|
|
segmentEnd: 100,
|
|
vttOffset: 0,
|
|
};
|
|
const textParser = new shaka.text.VttTextParser();
|
|
const cues = textParser.parseMedia(data, time);
|
|
helper.textDisplayer.append(cues);
|
|
}
|
|
});
|