shaka-player 4.3.2 → 4.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.github/workflows/selenium-lab-tests.yaml +22 -0
  2. package/CHANGELOG.md +37 -0
  3. package/dist/deps.js +4 -3
  4. package/dist/locales.js +33 -33
  5. package/dist/shaka-player.compiled.d.ts +10 -0
  6. package/dist/shaka-player.compiled.debug.d.ts +10 -0
  7. package/dist/shaka-player.compiled.debug.externs.js +12 -0
  8. package/dist/shaka-player.compiled.debug.js +152 -144
  9. package/dist/shaka-player.compiled.debug.map +4 -4
  10. package/dist/shaka-player.compiled.externs.js +12 -0
  11. package/dist/shaka-player.compiled.js +778 -772
  12. package/dist/shaka-player.compiled.map +4 -4
  13. package/dist/shaka-player.ui.d.ts +10 -0
  14. package/dist/shaka-player.ui.debug.d.ts +10 -0
  15. package/dist/shaka-player.ui.debug.externs.js +12 -0
  16. package/dist/shaka-player.ui.debug.js +164 -157
  17. package/dist/shaka-player.ui.debug.map +4 -4
  18. package/dist/shaka-player.ui.externs.js +12 -0
  19. package/dist/shaka-player.ui.js +851 -846
  20. package/dist/shaka-player.ui.map +4 -4
  21. package/lib/dash/segment_template.js +17 -5
  22. package/lib/hls/hls_parser.js +45 -16
  23. package/lib/media/media_source_engine.js +34 -4
  24. package/lib/media/segment_index.js +5 -10
  25. package/lib/media/segment_reference.js +39 -0
  26. package/lib/media/streaming_engine.js +15 -3
  27. package/lib/player.js +7 -1
  28. package/lib/polyfill/media_capabilities.js +4 -1
  29. package/lib/text/simple_text_displayer.js +2 -64
  30. package/lib/text/text_utils.js +88 -0
  31. package/lib/text/ui_text_displayer.js +24 -9
  32. package/lib/text/vtt_text_parser.js +224 -97
  33. package/lib/text/web_vtt_generator.js +2 -52
  34. package/lib/util/dom_utils.js +3 -1
  35. package/lib/util/platform.js +8 -0
  36. package/lib/util/stream_utils.js +6 -0
  37. package/lib/util/timer.js +17 -0
  38. package/package.json +1 -1
  39. package/support.html +1 -0
  40. package/test/dash/dash_parser_manifest_unit.js +0 -36
  41. package/test/hls/hls_live_unit.js +8 -30
  42. package/test/hls/hls_parser_unit.js +30 -0
  43. package/test/media/segment_index_unit.js +28 -0
  44. package/test/media/streaming_engine_unit.js +91 -119
  45. package/test/player_integration.js +27 -0
  46. package/test/player_unit.js +4 -2
  47. package/test/test/util/layout_tests.js +433 -0
  48. package/test/test/util/util.js +0 -120
  49. package/test/{ui → text}/text_displayer_layout_unit.js +59 -235
  50. package/test/text/ui_text_displayer_unit.js +72 -4
  51. package/test/text/vtt_text_parser_unit.js +114 -8
  52. package/test/text/web_vtt_layout_integration.js +528 -0
@@ -4,98 +4,30 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- // TODO: Move this suite to the text/ folder where it belongs
8
- const supportsScreenshots = () => shaka.test.Util.supportsScreenshots();
9
- filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
10
- const UiUtils = shaka.test.UiUtils;
11
- const Util = shaka.test.Util;
12
-
13
- /** @type {!shaka.extern.TextDisplayer} */
14
- let textDisplayer;
15
- /**
16
- * The video container or other element which is used for the screenshot.
17
- * @type {!HTMLElement}
18
- */
19
- let videoContainer;
20
- /**
21
- * Awaited before each screenshot, and can vary by test suite.
22
- * @type {function(number):!Promise}
23
- */
24
- let beforeScreenshot;
25
-
26
- // A minimum similarity score for screenshots, between 0 and 1.
27
- const minSimilarity = 0.95;
28
-
29
- const originalCast = window.chrome && window.chrome.cast;
30
-
7
+ filterDescribe('Cue layout', shaka.test.TextLayoutTests.supported, () => {
8
+ /** @type {shaka.test.TextLayoutTests} */
9
+ let helper;
31
10
 
32
11
  describe('using UI', () => {
33
- /** @type {!HTMLLinkElement} */
34
- let cssLink;
35
- /** @type {!shaka.test.FakeVideo} */
36
- let mockVideo;
37
-
38
- function createTextDisplayer() {
39
- textDisplayer = new shaka.text.UITextDisplayer(
40
- /** @type {!HTMLMediaElement} */(mockVideo),
41
- videoContainer);
42
- textDisplayer.setTextVisibility(true);
43
- }
44
-
45
12
  beforeAll(async () => {
46
- // Disable cast so the UI controls don't create cast sessions.
47
- if (window.chrome) {
48
- window.chrome['cast'] = null;
49
- }
50
-
51
- // Add css file
52
- cssLink = /** @type {!HTMLLinkElement} */(document.createElement('link'));
53
- await UiUtils.setupCSS(cssLink);
54
-
55
- // There's no actual video inside this container, but subtitles will be
56
- // positioned within this space.
57
- videoContainer = /** @type {!HTMLElement} */(
58
- document.createElement('div'));
59
- document.body.appendChild(videoContainer);
60
-
61
- positionElementForScreenshot(videoContainer);
13
+ helper = new shaka.test.DomTextLayoutTests('text-displayer-ui');
62
14
 
63
- // Some of the styles in our CSS are only applied within this class. Add
64
- // this explicitly, since we don't instantiate controls in all of the
65
- // tests.
66
- videoContainer.classList.add('shaka-video-container');
67
-
68
- await Util.waitForFont('Roboto');
69
-
70
- // eslint-disable-next-line require-await
71
- beforeScreenshot = async (time) => {
72
- // Set the faked time.
73
- mockVideo.currentTime = time;
74
-
75
- // Trigger the display update logic to notice the time change by
76
- // appending an empty array.
77
- textDisplayer.append([]);
78
- };
15
+ await helper.beforeAll();
79
16
  });
80
17
 
81
- beforeEach(() => {
82
- mockVideo = new shaka.test.FakeVideo();
83
- createTextDisplayer();
18
+ beforeEach(async () => {
19
+ await helper.beforeEach();
84
20
  });
85
21
 
86
22
  afterEach(async () => {
87
- await textDisplayer.destroy();
23
+ await helper.afterEach();
88
24
  });
89
25
 
90
- afterAll(() => {
91
- document.body.removeChild(videoContainer);
92
- document.head.removeChild(cssLink);
93
- if (window.chrome) {
94
- window.chrome['cast'] = originalCast;
95
- }
26
+ afterAll(async () => {
27
+ await helper.afterAll();
96
28
  });
97
29
 
98
- defineTests('ui');
30
+ defineTests();
99
31
 
100
32
  // This test is unique to the UI.
101
33
  it('moves cues to avoid controls', async () => {
@@ -107,7 +39,8 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
107
39
  // DOM and is purely temporary.
108
40
  const player = new shaka.Player(null);
109
41
  ui = new shaka.ui.Overlay(
110
- player, videoContainer, shaka.test.UiUtils.createVideoElement());
42
+ player, /** @type {!HTMLElement} */(helper.videoContainer),
43
+ shaka.test.UiUtils.createVideoElement());
111
44
  // Turn off every part of the UI that we can, so that the screenshot is
112
45
  // less likey to change because of something unrelated to text
113
46
  // rendering.
@@ -119,8 +52,8 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
119
52
  // Recreate the text displayer so that the text container comes after
120
53
  // the controls (as it does in production). This is important for the
121
54
  // CSS that moves the cues above the controls when they are shown.
122
- await textDisplayer.destroy();
123
- createTextDisplayer();
55
+ await helper.textDisplayer.destroy();
56
+ helper.recreateTextDisplayer();
124
57
 
125
58
  const cue = new shaka.text.Cue(
126
59
  0, 1, 'Captain\'s log, stardate 41636.9');
@@ -130,133 +63,61 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
130
63
  cue.region.viewportAnchorY = 90; // %
131
64
  cue.region.width = 100; // %
132
65
  cue.region.height = 10; // %
133
- textDisplayer.append([cue]);
66
+ helper.textDisplayer.append([cue]);
134
67
 
135
- await checkScreenshot('ui', 'cue-with-controls');
68
+ await helper.checkScreenshot('cue-with-controls');
136
69
  } finally {
137
70
  await ui.destroy();
138
71
  }
139
72
  });
140
73
  });
141
74
 
142
-
143
75
  describe('using browser-native rendering', () => {
144
- /** @type {!HTMLVideoElement} */
145
- let video;
146
-
147
76
  beforeAll(async () => {
148
- video = shaka.test.UiUtils.createVideoElement();
149
-
150
- // On some platforms, such as Chrome on Android, we may see a "cast"
151
- // button overlayed if this isn't set.
152
- video.disableRemotePlayback = true;
153
-
154
- document.body.appendChild(video);
155
-
156
- positionElementForScreenshot(video);
157
-
158
- const eventManager = new shaka.util.EventManager();
159
- const waiter = new shaka.test.Waiter(eventManager);
160
- const canPlay = waiter.failOnTimeout(false).timeoutAfter(10)
161
- .waitForEvent(video, 'canplay');
162
-
163
- // Video content is required to show native subtitles. This is a small
164
- // green frame.
165
- video.src = '/base/test/test/assets/green-pixel.mp4';
166
- await canPlay;
167
- expect(video.duration).toBeGreaterThan(0);
168
- expect(video.videoWidth).toBeGreaterThan(0);
169
-
170
- // There is no actual container. Screenshots will be taken of the video
171
- // element itself.
172
- videoContainer = video;
173
-
174
- // On Firefox, Safari, and legacy Edge, the video must be played a little
175
- // _after_ appending cues in order to consistently show subtitles
176
- // natively on the video element.
177
- beforeScreenshot = async (time) => {
178
- // Seek to the beginning so that we can reasonably wait for movement
179
- // after playing below. If somehow the playhead ends up at the end of
180
- // the video, we should seek back before we play.
181
- video.currentTime = 0;
182
-
183
- // The video must be played a little now, after the cues were appended,
184
- // but before the screenshot.
185
- video.playbackRate = 1;
186
- video.play();
187
- await waiter.failOnTimeout(false).timeoutAfter(5)
188
- .waitForMovement(video);
189
- video.pause();
190
-
191
- // Seek to a time when cues should be showing.
192
- video.currentTime = time;
193
- // Get into a playing state, but without movement.
194
- video.playbackRate = 0;
195
- video.play();
196
-
197
- // Add a short delay to ensure that the system has caught up and that
198
- // native text displayers have been updated by the browser.
199
- await Util.delay(0.1);
200
- };
77
+ helper = new shaka.test.NativeTextLayoutTests('text-displayer-native');
78
+
79
+ await helper.beforeAll();
201
80
  });
202
81
 
203
- beforeEach(() => {
204
- textDisplayer = new shaka.text.SimpleTextDisplayer(video);
205
- textDisplayer.setTextVisibility(true);
82
+ beforeEach(async () => {
83
+ await helper.beforeEach();
206
84
  });
207
85
 
208
86
  afterEach(async () => {
209
- await textDisplayer.destroy();
87
+ await helper.afterEach();
210
88
  });
211
89
 
212
- afterAll(() => {
213
- document.body.removeChild(video);
90
+ afterAll(async () => {
91
+ await helper.afterAll();
214
92
  });
215
93
 
216
- defineTests('native');
94
+ defineTests();
217
95
  });
218
96
 
219
-
220
- /** @param {string} prefix Prepended to screenshot names */
221
- function defineTests(prefix) {
222
- // Due to a Safari implementation bug, the browser only does the correct
223
- // thing for "end-time-edge-case" on Safari 16+. Skip the tests on earlier
224
- // versions.
225
- const safariVersion = shaka.util.Platform.safariVersion();
226
- if (prefix == 'native' && safariVersion && safariVersion < 16) {
227
- return;
228
- }
229
-
230
- // Due to updates in the rendering and/or default styles in Chrome, the
231
- // screenshots for native rendering only match in Chrome 106+.
232
- const chromeVersion = shaka.util.Platform.chromeVersion();
233
- if (prefix == 'native' && chromeVersion && chromeVersion < 106) {
234
- return;
235
- }
236
-
97
+ function defineTests() {
237
98
  it('basic cue', async () => {
238
- textDisplayer.append([
99
+ helper.textDisplayer.append([
239
100
  new shaka.text.Cue(0, 1, 'Captain\'s log, stardate 41636.9'),
240
101
  ]);
241
102
 
242
- await checkScreenshot(prefix, 'basic-cue');
103
+ await helper.checkScreenshot('basic-cue');
243
104
  });
244
105
 
245
106
  it('cue with newline', async () => {
246
- textDisplayer.append([
107
+ helper.textDisplayer.append([
247
108
  new shaka.text.Cue(0, 1, 'Captain\'s log,\nstardate 41636.9'),
248
109
  ]);
249
110
 
250
- await checkScreenshot(prefix, 'cue-with-newline');
111
+ await helper.checkScreenshot('cue-with-newline');
251
112
  });
252
113
 
253
114
  it('two basic cues', async () => {
254
- textDisplayer.append([
115
+ helper.textDisplayer.append([
255
116
  new shaka.text.Cue(0, 1, 'Captain\'s log,'),
256
117
  new shaka.text.Cue(0, 1, 'stardate 41636.9'),
257
118
  ]);
258
119
 
259
- await checkScreenshot(prefix, 'two-basic-cues');
120
+ await helper.checkScreenshot('two-basic-cues');
260
121
  });
261
122
 
262
123
  // Regression test for #2497
@@ -265,14 +126,14 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
265
126
  // In reality, this occurs when a VTT cue crossed a segment boundary and
266
127
  // appears in more than one segment. So we must simulate this with two
267
128
  // calls to append().
268
- textDisplayer.append([
129
+ helper.textDisplayer.append([
269
130
  new shaka.text.Cue(0, 1, 'Captain\'s log, stardate 41636.9'),
270
131
  ]);
271
- textDisplayer.append([
132
+ helper.textDisplayer.append([
272
133
  new shaka.text.Cue(0, 1, 'Captain\'s log, stardate 41636.9'),
273
134
  ]);
274
135
 
275
- await checkScreenshot(prefix, 'duplicate-cues');
136
+ await helper.checkScreenshot('duplicate-cues');
276
137
  });
277
138
 
278
139
  // Regression test for #3151
@@ -283,15 +144,15 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
283
144
  // through the UI & DOM, we can always get the timing right.
284
145
  it('cues ending exactly now', async () => {
285
146
  // At time exactly 1, this cue should _not_ be displayed any more.
286
- textDisplayer.append([
147
+ helper.textDisplayer.append([
287
148
  new shaka.text.Cue(0, 1, 'This cue is over and gone.'),
288
149
  ]);
289
150
  // At time exactly 1, this cue should _just_ be starting.
290
- textDisplayer.append([
151
+ helper.textDisplayer.append([
291
152
  new shaka.text.Cue(1, 2, 'This cue is just starting.'),
292
153
  ]);
293
154
 
294
- await checkScreenshot(prefix, 'end-time-edge-case', /* time= */ 1);
155
+ await helper.checkScreenshot('end-time-edge-case', /* time= */ 1);
295
156
  });
296
157
 
297
158
  // Regression test for #2524
@@ -301,9 +162,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
301
162
  new shaka.text.Cue(0, 1, 'Captain\'s log, '),
302
163
  new shaka.text.Cue(0, 1, 'stardate 41636.9'),
303
164
  ];
304
- textDisplayer.append([cue]);
165
+ helper.textDisplayer.append([cue]);
305
166
 
306
- await checkScreenshot(prefix, 'two-nested-cues');
167
+ await helper.checkScreenshot('two-nested-cues');
307
168
  });
308
169
 
309
170
  // Distinct from "newline" test above, which has a literal \n character in
@@ -316,9 +177,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
316
177
  shaka.text.Cue.lineBreak(0, 1),
317
178
  new shaka.text.Cue(0, 1, 'stardate 41636.9'),
318
179
  ];
319
- textDisplayer.append([cue]);
180
+ helper.textDisplayer.append([cue]);
320
181
 
321
- await checkScreenshot(prefix, 'nested-cues-with-linebreak');
182
+ await helper.checkScreenshot('nested-cues-with-linebreak');
322
183
  });
323
184
 
324
185
  // Regression test for #3600
@@ -326,9 +187,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
326
187
  const cue = new shaka.text.Cue(0, 1, 'Text');
327
188
  cue.line = 10;
328
189
  cue.lineInterpretation = shaka.text.Cue.lineInterpretation.PERCENTAGE;
329
- textDisplayer.append([cue]);
190
+ helper.textDisplayer.append([cue]);
330
191
 
331
- await checkScreenshot(prefix, 'cue-position');
192
+ await helper.checkScreenshot('cue-position');
332
193
  });
333
194
 
334
195
  // Regression test for #2157 and #2584
@@ -343,9 +204,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
343
204
  cue.region.width = 30; // %
344
205
  cue.region.height = 65; // %
345
206
  cue.nestedCues = [nestedCue];
346
- textDisplayer.append([cue]);
207
+ helper.textDisplayer.append([cue]);
347
208
 
348
- await checkScreenshot(prefix, 'region-position');
209
+ await helper.checkScreenshot('region-position');
349
210
  });
350
211
 
351
212
  // Regression test for #3379, in which the displayAlign was not respected,
@@ -367,9 +228,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
367
228
  // For those who don't speak Unicode, \xbf is an upside down "?".
368
229
  new shaka.text.Cue(0, 1, '\xbfBien?'),
369
230
  ];
370
- textDisplayer.append([cue]);
231
+ helper.textDisplayer.append([cue]);
371
232
 
372
- await checkScreenshot(prefix, 'region-with-display-alignment');
233
+ await helper.checkScreenshot('region-with-display-alignment');
373
234
  });
374
235
 
375
236
  // Regression test for #2188
@@ -381,9 +242,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
381
242
  cue.region.viewportAnchorY = 10; // %
382
243
  // eslint-disable-next-line max-len
383
244
  cue.backgroundImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAAA8BAMAAABMVCNvAAAAElBMVEX9/vtRldU+uUv6vAnvNjWzvsvH461AAAABvUlEQVRIx7WWwY6CMBRFYQb2Nhn22sS9o5m9icy+aPn/X5lS6r221gfTxLsC0pN7XovE6j1p9d6UcB/apYTUU/YlhT7bArCwUocUg9sCsMxVF7i2Pwd3+v93/Ty5uEbZtVVd+nacphw08oJzMUmhzxWgyYHDBHbRo9sMHmVX5bOJTENyrq0rMjB1EUG61ipMBtBEYM41qakVXLk3eVdyagMQrqNB47ProO4hGCbu+/4MMHUlp6J2F8c58pR3bRVj/B1cm94nB2IlatSDq53BW8Z1i4UEed3PueQqhxTkA781L10JBb2aNwAvGdddAj66NhKon0C6onHZtXKhKxolVx46XbtyUHLdRaaxqyXISoBxYfQOftFVBPnZuSfrSpCFcBXAYwp2HlrtSrBi1BrXlFt2RSEGXOn6DRCc6EpQgYMoXGWQIbLsSpCizAOIABQ4yZVgV2VAwfXlgPJvi6DJgnUGvMEUA0qgBTh6cOCAsmsD8LdDIQYUKiuA50FdBwy4DFqAtXCCDMAGYEtOCDYBrgYfFfn/G0ALsAInVgYruIaHnQSxcroKI1ZrU9/PuQmmq9OO43xhhUI5jR3lBX8x/RKsZNOu/wAAAABJRU5ErkJggg==';
384
- textDisplayer.append([cue]);
245
+ helper.textDisplayer.append([cue]);
385
246
 
386
- await checkScreenshot(prefix, 'bitmap-cue');
247
+ await helper.checkScreenshot('bitmap-cue');
387
248
  });
388
249
 
389
250
  // Used to be a regression test for #2623, but that should have been fixed
@@ -405,9 +266,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
405
266
  cue.nestedCues[2].backgroundColor = 'yellow';
406
267
  cue.backgroundColor = 'purple';
407
268
 
408
- textDisplayer.append([cue]);
269
+ helper.textDisplayer.append([cue]);
409
270
 
410
- await checkScreenshot(prefix, 'nested-cue-bg');
271
+ await helper.checkScreenshot('nested-cue-bg');
411
272
  });
412
273
 
413
274
  it('colors background for flat cues', async () => {
@@ -415,9 +276,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
415
276
  // This is shown.
416
277
  cue.backgroundColor = 'purple';
417
278
 
418
- textDisplayer.append([cue]);
279
+ helper.textDisplayer.append([cue]);
419
280
 
420
- await checkScreenshot(prefix, 'flat-cue-bg');
281
+ await helper.checkScreenshot('flat-cue-bg');
421
282
  });
422
283
 
423
284
  // https://github.com/shaka-project/shaka-player/issues/2761
@@ -440,9 +301,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
440
301
  ]),
441
302
  ]);
442
303
 
443
- textDisplayer.append([cue]);
304
+ helper.textDisplayer.append([cue]);
444
305
 
445
- await checkScreenshot(prefix, 'deeply-nested-cues');
306
+ await helper.checkScreenshot('deeply-nested-cues');
446
307
  });
447
308
 
448
309
  // Regression test for #4567, in which "end" line alignment for VTT was
@@ -454,46 +315,9 @@ filterDescribe('TextDisplayer layout', supportsScreenshots, () => {
454
315
  cue.lineInterpretation = shaka.text.Cue.lineInterpretation.PERCENTAGE;
455
316
  cue.lineAlign = shaka.text.Cue.lineAlign.END;
456
317
 
457
- textDisplayer.append([cue]);
318
+ helper.textDisplayer.append([cue]);
458
319
 
459
- await checkScreenshot(prefix, 'line-alignment');
320
+ await helper.checkScreenshot('line-alignment');
460
321
  });
461
322
  }
462
-
463
- /** @param {!HTMLElement} element */
464
- function positionElementForScreenshot(element) {
465
- // The element we screenshot will be 16:9 and small.
466
- element.style.width = '320px';
467
- element.style.height = '180px';
468
-
469
- // The background is green so we can better see the background color of
470
- // the text spans within the subtitles, and so it is easier to identify
471
- // cropping issues.
472
- element.style.backgroundColor = 'green';
473
-
474
- // Make sure the element is in the top-left corner of the iframe that
475
- // contains the tests.
476
- element.style.top = '0';
477
- element.style.left = '0';
478
- element.style.position = 'fixed';
479
- element.style.margin = '0';
480
- element.style.padding = '0';
481
- }
482
-
483
- /**
484
- * @param {string} prefix A prefix added to the screenshot name with a hyphen
485
- * to provide context.
486
- * @param {string} baseName The base name of the screenshot.
487
- * @param {number=} time The time to seek to in the screenshot. Defaults to
488
- * 0.1, when most of our tests will be showing cues (timed 0-1).
489
- * @return {!Promise}
490
- */
491
- async function checkScreenshot(prefix, baseName, time=0.1) {
492
- await beforeScreenshot(time);
493
-
494
- return Util.checkScreenshot(
495
- /* element= */ videoContainer,
496
- prefix + '-' + baseName,
497
- minSimilarity);
498
- }
499
323
  });
@@ -338,15 +338,13 @@ describe('UITextDisplayer', () => {
338
338
  it('hides and shows nested cues at appropriate times', () => {
339
339
  const parentCue1 = new shaka.text.Cue(0, 100, '');
340
340
  const cue1 = new shaka.text.Cue(0, 50, 'One');
341
- parentCue1.nestedCues.push(cue1);
342
341
  const cue2 = new shaka.text.Cue(25, 75, 'Two');
343
- parentCue1.nestedCues.push(cue2);
344
342
  const cue3 = new shaka.text.Cue(50, 100, 'Three');
345
- parentCue1.nestedCues.push(cue3);
343
+ parentCue1.nestedCues = [cue1, cue2, cue3];
346
344
 
347
345
  const parentCue2 = new shaka.text.Cue(90, 190, '');
348
346
  const cue4 = new shaka.text.Cue(90, 130, 'Four');
349
- parentCue2.nestedCues.push(cue4);
347
+ parentCue2.nestedCues = [cue4];
350
348
 
351
349
  textDisplayer.setTextVisibility(true);
352
350
  textDisplayer.append([parentCue1, parentCue2]);
@@ -537,4 +535,74 @@ describe('UITextDisplayer', () => {
537
535
  '.shaka-text-region');
538
536
  expect(allRegionElements.length).toBe(1);
539
537
  });
538
+
539
+ it('creates separate regions when dimensions differ but id same', () => {
540
+ const identicalRegionId = 'regionId';
541
+
542
+ const cueRegion1 = new shaka.text.CueRegion();
543
+ const cueRegion2 = new shaka.text.CueRegion();
544
+ cueRegion1.id = identicalRegionId;
545
+ cueRegion2.id = identicalRegionId;
546
+
547
+ cueRegion1.height = 80;
548
+ cueRegion1.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
549
+ cueRegion1.width = 80;
550
+ cueRegion1.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
551
+
552
+ cueRegion2.height = 160; // the only difference!
553
+ cueRegion2.heightUnits = shaka.text.CueRegion.units.PERCENTAGE;
554
+ cueRegion2.width = 80;
555
+ cueRegion2.widthUnits = shaka.text.CueRegion.units.PERCENTAGE;
556
+
557
+ cueRegion1.viewportAnchorX = 10;
558
+ cueRegion1.viewportAnchorY = 10;
559
+ cueRegion1.viewportAnchorUnits = shaka.text.CueRegion.units.PERCENTAGE;
560
+
561
+ cueRegion2.viewportAnchorX = 10;
562
+ cueRegion2.viewportAnchorY = 10;
563
+ cueRegion2.viewportAnchorUnits = shaka.text.CueRegion.units.PERCENTAGE;
564
+
565
+ // These all attach to the same region, but only one region element should
566
+ // be created.
567
+ const firstBatchOfCues = [
568
+ new shaka.text.Cue(0, 100, ''),
569
+ new shaka.text.Cue(0, 100, ''),
570
+ new shaka.text.Cue(0, 100, ''),
571
+ ];
572
+ for (const cue of firstBatchOfCues) {
573
+ cue.displayAlign = shaka.text.Cue.displayAlign.CENTER;
574
+ cue.region = cueRegion1;
575
+ }
576
+
577
+ // Another batch for the other region
578
+ const secondBatchOfCues = [
579
+ new shaka.text.Cue(0, 100, ''),
580
+ new shaka.text.Cue(0, 100, ''),
581
+ new shaka.text.Cue(0, 100, ''),
582
+ ];
583
+ for (const cue of secondBatchOfCues) {
584
+ cue.displayAlign = shaka.text.Cue.displayAlign.CENTER;
585
+ cue.region = cueRegion2;
586
+ }
587
+
588
+ textDisplayer.setTextVisibility(true);
589
+ textDisplayer.append(firstBatchOfCues);
590
+ textDisplayer.append(secondBatchOfCues);
591
+ updateCaptions();
592
+
593
+ const textContainer = videoContainer.querySelector('.shaka-text-container');
594
+ const allRegionElements = textContainer.querySelectorAll(
595
+ '.shaka-text-region');
596
+
597
+ // Verify that the nested cues are attached to respective region element.
598
+ expect(allRegionElements.length).toBe(2);
599
+
600
+ const childrenOfOne = Array.from(allRegionElements[0].childNodes).filter(
601
+ (e) => e.nodeType == Node.ELEMENT_NODE);
602
+ expect(childrenOfOne.length).toBe(3);
603
+
604
+ const childrenOfTwo = Array.from(allRegionElements[1].childNodes).filter(
605
+ (e) => e.nodeType == Node.ELEMENT_NODE);
606
+ expect(childrenOfTwo.length).toBe(3);
607
+ });
540
608
  });