shaka-player 3.2.1 → 3.3.1

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 (213) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/AUTHORS +9 -5
  5. package/CHANGELOG.md +358 -0
  6. package/CONTRIBUTORS +7 -2
  7. package/build/conformance.textproto +183 -169
  8. package/build/generateExterns.js +1 -1
  9. package/build/types/core +3 -0
  10. package/build/types/offline +1 -0
  11. package/build/types/polyfill +1 -0
  12. package/build/types/ui +2 -0
  13. package/demo/common/assets.js +19 -1
  14. package/demo/common/message_ids.js +13 -1
  15. package/demo/config.js +31 -1
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +12 -0
  18. package/demo/locales/source.json +48 -0
  19. package/dist/controls.css +26 -2
  20. package/dist/controls.css.map +1 -1
  21. package/dist/demo.compiled.debug.js +20 -17
  22. package/dist/demo.compiled.debug.map +3 -3
  23. package/dist/demo.compiled.js +20 -17
  24. package/dist/demo.compiled.map +3 -3
  25. package/dist/deps.js +19 -12
  26. package/dist/locales.js +39 -37
  27. package/dist/receiver.compiled.debug.js +12 -10
  28. package/dist/receiver.compiled.debug.map +3 -3
  29. package/dist/receiver.compiled.js +12 -10
  30. package/dist/receiver.compiled.map +3 -3
  31. package/dist/shaka-player.compiled.d.ts +231 -18
  32. package/dist/shaka-player.compiled.debug.d.ts +231 -18
  33. package/dist/shaka-player.compiled.debug.externs.js +279 -8
  34. package/dist/shaka-player.compiled.debug.js +512 -449
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +279 -8
  37. package/dist/shaka-player.compiled.js +854 -821
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +247 -19
  40. package/dist/shaka-player.ui.debug.d.ts +247 -19
  41. package/dist/shaka-player.ui.debug.externs.js +307 -9
  42. package/dist/shaka-player.ui.debug.js +662 -580
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +307 -9
  45. package/dist/shaka-player.ui.js +1047 -1000
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/bg-fetch-after.gv +29 -0
  48. package/docs/design/bg-fetch-after.gv.png +0 -0
  49. package/docs/design/bg-fetch-before.gv +18 -0
  50. package/docs/design/bg-fetch-before.gv.png +0 -0
  51. package/docs/design/bg-fetch.md +134 -0
  52. package/docs/tutorials/blob-url.md +15 -0
  53. package/docs/tutorials/fairplay.md +1 -1
  54. package/docs/tutorials/index.json +1 -0
  55. package/docs/tutorials/ui-customization.md +66 -0
  56. package/docs/tutorials/ui.md +5 -5
  57. package/externs/cmcd.js +186 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +5 -0
  60. package/externs/shaka/manifest.js +12 -1
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +31 -2
  64. package/externs/shaka/player.js +138 -5
  65. package/externs/shaka/text.js +24 -0
  66. package/externs/webcrypto.js +18 -0
  67. package/karma.conf.js +1 -0
  68. package/lib/abr/ewma.js +14 -0
  69. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  70. package/lib/abr/simple_abr_manager.js +6 -0
  71. package/lib/ads/client_side_ad.js +8 -0
  72. package/lib/ads/client_side_ad_manager.js +54 -90
  73. package/lib/ads/server_side_ad.js +7 -0
  74. package/lib/ads/server_side_ad_manager.js +7 -10
  75. package/lib/cast/cast_proxy.js +3 -2
  76. package/lib/cast/cast_receiver.js +2 -1
  77. package/lib/cast/cast_sender.js +2 -2
  78. package/lib/cast/cast_utils.js +1 -0
  79. package/lib/dash/dash_parser.js +141 -16
  80. package/lib/dash/segment_base.js +25 -1
  81. package/lib/dash/segment_list.js +19 -10
  82. package/lib/dash/segment_template.js +24 -11
  83. package/lib/hls/hls_parser.js +146 -40
  84. package/lib/media/drm_engine.js +7 -0
  85. package/lib/media/gap_jumping_controller.js +4 -2
  86. package/lib/media/media_source_engine.js +1 -2
  87. package/lib/media/quality_observer.js +291 -0
  88. package/lib/media/segment_index.js +8 -1
  89. package/lib/media/segment_reference.js +37 -4
  90. package/lib/media/streaming_engine.js +49 -7
  91. package/lib/net/http_fetch_plugin.js +31 -11
  92. package/lib/net/http_plugin_utils.js +1 -0
  93. package/lib/net/http_xhr_plugin.js +40 -14
  94. package/lib/net/networking_engine.js +83 -19
  95. package/lib/offline/download_info.js +68 -0
  96. package/lib/offline/download_manager.js +13 -5
  97. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  98. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  99. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  100. package/lib/offline/storage.js +393 -284
  101. package/lib/offline/stored_content_utils.js +2 -0
  102. package/lib/player.js +249 -43
  103. package/lib/polyfill/media_capabilities.js +36 -15
  104. package/lib/polyfill/mediasource.js +6 -0
  105. package/lib/polyfill/orientation.js +1 -1
  106. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  107. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  108. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  109. package/lib/polyfill/random_uuid.js +52 -0
  110. package/lib/text/cue.js +18 -0
  111. package/lib/text/mp4_ttml_parser.js +3 -0
  112. package/lib/text/text_engine.js +14 -2
  113. package/lib/text/ttml_text_parser.js +114 -60
  114. package/lib/text/ui_text_displayer.js +95 -41
  115. package/lib/util/cmcd_manager.js +672 -0
  116. package/lib/util/error.js +6 -0
  117. package/lib/util/fake_event.js +53 -7
  118. package/lib/util/language_utils.js +12 -0
  119. package/lib/util/mutex.js +52 -0
  120. package/lib/util/periods.js +102 -65
  121. package/lib/util/platform.js +13 -1
  122. package/lib/util/player_configuration.js +18 -0
  123. package/lib/util/stream_utils.js +99 -10
  124. package/lib/util/xml_utils.js +19 -0
  125. package/package.json +2 -2
  126. package/shaka-player.uncompiled.js +3 -0
  127. package/test/cast/cast_proxy_unit.js +12 -6
  128. package/test/cast/cast_utils_unit.js +1 -1
  129. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  130. package/test/dash/dash_parser_live_unit.js +101 -1
  131. package/test/dash/dash_parser_manifest_unit.js +222 -2
  132. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  133. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  134. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  135. package/test/hls/hls_live_unit.js +2 -0
  136. package/test/hls/hls_parser_unit.js +7 -1
  137. package/test/media/closed_caption_parser_unit.js +6 -1
  138. package/test/media/drm_engine_unit.js +47 -3
  139. package/test/media/quality_observer_unit.js +139 -0
  140. package/test/media/segment_reference_unit.js +16 -1
  141. package/test/media/streaming_engine_integration.js +4 -2
  142. package/test/media/streaming_engine_unit.js +147 -0
  143. package/test/net/http_plugin_unit.js +20 -15
  144. package/test/offline/storage_integration.js +108 -4
  145. package/test/player_integration.js +178 -8
  146. package/test/player_src_equals_integration.js +41 -8
  147. package/test/player_unit.js +19 -9
  148. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  149. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  150. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  151. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  152. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  153. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  154. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  155. package/test/test/assets/3675/dash_0.mpd +30 -0
  156. package/test/test/assets/3675/dash_1.mpd +30 -0
  157. package/test/test/assets/3675/dash_2.mpd +30 -0
  158. package/test/test/assets/3675/dash_3.mpd +30 -0
  159. package/test/test/assets/3675/dash_4.mpd +30 -0
  160. package/test/test/assets/3675/dash_5.mpd +26 -0
  161. package/test/test/assets/3675/init-stream0.m4s +0 -0
  162. package/test/test/assets/chapters.vtt +2 -2
  163. package/test/test/assets/chapters2.vtt +10 -0
  164. package/test/test/util/dash_parser_util.js +4 -0
  165. package/test/test/util/fake_ad.js +7 -0
  166. package/test/test/util/fake_ad_manager.js +1 -1
  167. package/test/test/util/fake_drm_engine.js +9 -2
  168. package/test/test/util/manifest_generator.js +3 -2
  169. package/test/test/util/test_scheme.js +14 -1
  170. package/test/test/util/ttml_utils.js +81 -0
  171. package/test/text/mp4_ttml_parser_unit.js +11 -18
  172. package/test/text/ttml_text_parser_unit.js +552 -227
  173. package/test/text/ui_text_displayer_unit.js +29 -17
  174. package/test/ui/localization_unit.js +15 -14
  175. package/test/ui/text_displayer_layout_unit.js +13 -1
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +291 -0
  178. package/test/util/stream_utils_unit.js +45 -4
  179. package/third_party/closure-uri/uri.js +21 -0
  180. package/ui/airplay_button.js +1 -0
  181. package/ui/audio_language_selection.js +7 -0
  182. package/ui/cast_button.js +3 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +45 -13
  185. package/ui/controls.less +1 -0
  186. package/ui/enums.js +4 -0
  187. package/ui/externs/ui.js +28 -1
  188. package/ui/fast_forward_button.js +14 -5
  189. package/ui/fullscreen_button.js +1 -0
  190. package/ui/less/buttons.less +0 -4
  191. package/ui/less/containers.less +77 -7
  192. package/ui/less/overflow_menu.less +0 -10
  193. package/ui/less/tooltip.less +97 -0
  194. package/ui/locales/en.json +1 -0
  195. package/ui/locales/ru.json +6 -6
  196. package/ui/locales/source.json +4 -0
  197. package/ui/localization.js +28 -51
  198. package/ui/loop_button.js +5 -0
  199. package/ui/mute_button.js +2 -1
  200. package/ui/overflow_menu.js +5 -25
  201. package/ui/pip_button.js +7 -3
  202. package/ui/play_button.js +2 -2
  203. package/ui/playback_rate_selection.js +8 -9
  204. package/ui/resolution_selection.js +7 -0
  205. package/ui/rewind_button.js +15 -6
  206. package/ui/seek_bar.js +4 -2
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/statistics_button.js +253 -0
  210. package/ui/text_selection.js +12 -4
  211. package/ui/ui.js +30 -0
  212. package/ui/volume_bar.js +1 -1
  213. package/externs/media_capabilities.js +0 -16
@@ -167,9 +167,14 @@ shaka.text.UITextDisplayer = class {
167
167
  }
168
168
 
169
169
  // Remove the cues out of the time range.
170
+ const oldNumCues = this.cues_.length;
170
171
  this.cues_ = this.cues_.filter(
171
172
  (cue) => cue.startTime < start || cue.endTime >= end);
172
- this.updateCaptions_();
173
+ // If anything was actually removed in this process, force the captions to
174
+ // update. This makes sure that the currently-displayed cues will stop
175
+ // displaying if removed (say, due to the user changing languages).
176
+ const forceUpdate = oldNumCues > this.cues_.length;
177
+ this.updateCaptions_(forceUpdate);
173
178
 
174
179
  return true;
175
180
  }
@@ -192,13 +197,13 @@ shaka.text.UITextDisplayer = class {
192
197
  }
193
198
 
194
199
  /**
195
- * @param {!Array.<!shaka.text.Cue>} cues
200
+ * @param {!Array.<!shaka.extern.Cue>} cues
196
201
  * @param {!HTMLElement} container
197
202
  * @param {number} currentTime
198
- * @param {boolean} isNested
203
+ * @param {!Array.<!shaka.extern.Cue>} parents
199
204
  * @private
200
205
  */
201
- updateCuesRecursive_(cues, container, currentTime, isNested) {
206
+ updateCuesRecursive_(cues, container, currentTime, parents) {
202
207
  // Set to true if the cues have changed in some way, which will require
203
208
  // DOM changes. E.g. if a cue was added or removed.
204
209
  let updateDOM = false;
@@ -214,10 +219,12 @@ shaka.text.UITextDisplayer = class {
214
219
  * The cues whose corresponding elements should be in the DOM.
215
220
  * Some of these might be new, some might have been displayed beforehand.
216
221
  * These will only be added if updateDOM is true.
217
- * @type {!Array.<!shaka.text.Cue>}
222
+ * @type {!Array.<!shaka.extern.Cue>}
218
223
  */
219
224
  const toPlant = [];
220
225
  for (const cue of cues) {
226
+ parents.push(cue);
227
+
221
228
  let cueRegistry = this.currentCuesMap_.get(cue);
222
229
  const shouldBeDisplayed =
223
230
  cue.startTime <= currentTime && cue.endTime > currentTime;
@@ -241,7 +248,7 @@ shaka.text.UITextDisplayer = class {
241
248
  toPlant.push(cue);
242
249
  if (!cueRegistry) {
243
250
  // The cue has to be made!
244
- this.createCue_(cue, isNested);
251
+ this.createCue_(cue, parents);
245
252
  cueRegistry = this.currentCuesMap_.get(cue);
246
253
  wrapper = cueRegistry.wrapper;
247
254
  updateDOM = true;
@@ -255,8 +262,11 @@ shaka.text.UITextDisplayer = class {
255
262
  // guaranteed that the children will neither need to be added nor removed.
256
263
  if (cue.nestedCues.length > 0 && wrapper) {
257
264
  this.updateCuesRecursive_(
258
- cue.nestedCues, wrapper, currentTime, /* isNested= */ true);
265
+ cue.nestedCues, wrapper, currentTime, parents);
259
266
  }
267
+
268
+ const topCue = parents.pop();
269
+ goog.asserts.assert(topCue == cue, 'Parent cues should be kept in order');
260
270
  }
261
271
  if (updateDOM) {
262
272
  for (const cueElement of toUproot) {
@@ -304,7 +314,7 @@ shaka.text.UITextDisplayer = class {
304
314
 
305
315
  // Update the cues.
306
316
  this.updateCuesRecursive_(
307
- this.cues_, this.textContainer_, currentTime, false);
317
+ this.cues_, this.textContainer_, currentTime, /* parents= */ []);
308
318
 
309
319
  if (goog.DEBUG) {
310
320
  // Previously, we had an issue (#2076) where cues sometimes were not
@@ -327,10 +337,11 @@ shaka.text.UITextDisplayer = class {
327
337
  * Creates the object for a cue.
328
338
  *
329
339
  * @param {!shaka.extern.Cue} cue
330
- * @param {boolean} isNested
340
+ * @param {!Array.<!shaka.extern.Cue>} parents
331
341
  * @private
332
342
  */
333
- createCue_(cue, isNested) {
343
+ createCue_(cue, parents) {
344
+ const isNested = parents.length > 1;
334
345
  let type = isNested ? 'span' : 'div';
335
346
  if (cue.lineBreak || cue.spacer) {
336
347
  if (cue.spacer) {
@@ -341,19 +352,22 @@ shaka.text.UITextDisplayer = class {
341
352
  type = 'br';
342
353
  }
343
354
 
355
+ const needWrapper = !isNested && cue.nestedCues.length > 0;
356
+
344
357
  // Nested cues are inline elements. Top-level cues are block elements.
345
358
  const cueElement = shaka.util.Dom.createHTMLElement(type);
346
359
  if (type != 'br') {
347
- this.setCaptionStyles_(cueElement, cue, isNested);
360
+ this.setCaptionStyles_(cueElement, cue, parents, needWrapper);
348
361
  }
349
362
 
350
363
  let wrapper = cueElement;
351
- if (!isNested && cue.nestedCues.length) {
364
+ if (needWrapper) {
352
365
  // Create a wrapper element which will serve to contain all children into
353
366
  // a single item. This ensures that nested span elements appear
354
367
  // horizontally and br elements occupy no vertical space.
355
368
  wrapper = shaka.util.Dom.createHTMLElement('span');
356
369
  wrapper.classList.add('shaka-text-wrapper');
370
+ wrapper.style.backgroundColor = cue.backgroundColor;
357
371
  cueElement.appendChild(wrapper);
358
372
  }
359
373
 
@@ -363,13 +377,17 @@ shaka.text.UITextDisplayer = class {
363
377
  /**
364
378
  * @param {!HTMLElement} cueElement
365
379
  * @param {!shaka.extern.Cue} cue
366
- * @param {boolean} isNested
380
+ * @param {!Array.<!shaka.extern.Cue>} parents
381
+ * @param {boolean} hasWrapper
367
382
  * @private
368
383
  */
369
- setCaptionStyles_(cueElement, cue, isNested) {
384
+ setCaptionStyles_(cueElement, cue, parents, hasWrapper) {
370
385
  const Cue = shaka.text.Cue;
371
- let style = cueElement.style;
386
+ const inherit =
387
+ (cb) => shaka.text.UITextDisplayer.inheritProperty_(parents, cb);
388
+ const style = cueElement.style;
372
389
  const isLeaf = cue.nestedCues.length == 0;
390
+ const isNested = parents.length > 1;
373
391
 
374
392
  // TODO: wrapLine is not yet supported. Lines always wrap.
375
393
 
@@ -388,45 +406,57 @@ shaka.text.UITextDisplayer = class {
388
406
  const nonBreakingSpace = '\xa0';
389
407
  return nonBreakingSpace.repeat(match.length);
390
408
  });
391
- if (isNested) {
392
- cueElement.textContent = text;
393
- } else if (text.length) {
394
- // If a top-level cue has text, move to a <span> so the background is
395
- // styled correctly.
396
- const span = shaka.util.Dom.createHTMLElement('span');
397
- span.textContent = text;
398
- cueElement.appendChild(span);
399
- style = span.style;
400
- }
401
409
 
402
- style.backgroundColor = cue.backgroundColor;
403
- style.border = cue.border;
410
+ style.webkitTextStrokeColor = cue.textStrokeColor;
411
+ style.webkitTextStrokeWidth = cue.textStrokeWidth;
404
412
  style.color = cue.color;
405
413
  style.direction = cue.direction;
406
414
  style.opacity = cue.opacity;
407
415
  style.paddingLeft = shaka.text.UITextDisplayer.convertLengthValue_(
408
416
  cue.linePadding, cue, this.videoContainer_);
409
- style.paddingRight = shaka.text.UITextDisplayer.convertLengthValue_(
410
- cue.linePadding, cue, this.videoContainer_);
417
+ style.paddingRight =
418
+ shaka.text.UITextDisplayer.convertLengthValue_(
419
+ cue.linePadding, cue, this.videoContainer_);
411
420
 
412
421
  if (cue.backgroundImage) {
413
422
  style.backgroundImage = 'url(\'' + cue.backgroundImage + '\')';
414
423
  style.backgroundRepeat = 'no-repeat';
415
424
  style.backgroundSize = 'contain';
416
425
  style.backgroundPosition = 'center';
426
+ } else {
427
+ // If we have both text and nested cues, then style everything; otherwise
428
+ // place the text in its own <span> so the background doesn't fill the
429
+ // whole region.
430
+ let elem;
431
+ if (cue.nestedCues.length) {
432
+ elem = cueElement;
433
+ } else {
434
+ elem = shaka.util.Dom.createHTMLElement('span');
435
+ cueElement.appendChild(elem);
436
+ }
417
437
 
418
- if (cue.backgroundColor == '') {
419
- // In text-based cues, background color can default in CSS.
420
- // In bitmap-based cues, we default to a transparent background color,
421
- // so that the bitmap can be the only background.
422
- style.backgroundColor = 'transparent';
438
+ if (cue.border) {
439
+ elem.style.border = cue.border;
440
+ }
441
+ if (!hasWrapper) {
442
+ const bgColor = inherit((c) => c.backgroundColor);
443
+ if (bgColor) {
444
+ elem.style.backgroundColor = bgColor;
445
+ } else if (text) {
446
+ // If there is no background, default to a semi-transparent black.
447
+ // Only do this for the text itself.
448
+ elem.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
449
+ }
450
+ }
451
+ if (text) {
452
+ elem.textContent = text;
423
453
  }
424
454
  }
425
455
 
426
456
  // The displayAlign attribute specifies the vertical alignment of the
427
457
  // captions inside the text container. Before means at the top of the
428
458
  // text container, and after means at the bottom.
429
- if (isNested) {
459
+ if (isNested && !parents[parents.length - 1].isContainer) {
430
460
  style.display = 'inline';
431
461
  } else {
432
462
  style.display = 'flex';
@@ -472,20 +502,28 @@ shaka.text.UITextDisplayer = class {
472
502
  // TODO: Implement lineAlignment of 'CENTER'.
473
503
  if (cue.line) {
474
504
  if (cue.lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
505
+ // When setting absolute positioning, you need to set x/y/width/height
506
+ // so the element is positioned correctly. Set these as default and
507
+ // other settings will override them.
475
508
  style.position = 'absolute';
509
+ style.left = '0';
510
+ style.top = '0';
476
511
  if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
512
+ style.width = '100%';
477
513
  if (cue.lineAlign == Cue.lineAlign.START) {
478
514
  style.top = cue.line + '%';
479
515
  } else if (cue.lineAlign == Cue.lineAlign.END) {
480
516
  style.bottom = cue.line + '%';
481
517
  }
482
518
  } else if (cue.writingMode == Cue.writingMode.VERTICAL_LEFT_TO_RIGHT) {
519
+ style.height = '100%';
483
520
  if (cue.lineAlign == Cue.lineAlign.START) {
484
521
  style.left = cue.line + '%';
485
522
  } else if (cue.lineAlign == Cue.lineAlign.END) {
486
523
  style.right = cue.line + '%';
487
524
  }
488
525
  } else {
526
+ style.height = '100%';
489
527
  if (cue.lineAlign == Cue.lineAlign.START) {
490
528
  style.right = cue.line + '%';
491
529
  } else if (cue.lineAlign == Cue.lineAlign.END) {
@@ -493,12 +531,7 @@ shaka.text.UITextDisplayer = class {
493
531
  }
494
532
  }
495
533
  }
496
- } else if (cue.region && cue.region.id &&
497
- ((!isNested && !isLeaf) || (cue.backgroundImage))) {
498
- // In text-base cues, regions are only applied to block container
499
- // (!isNested && !isLeaf).
500
- // In bitmap-based cues, region settings are used to specify the size and
501
- // position of the backgroundImage.
534
+ } else if (cue.region && cue.region.id) {
502
535
  const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
503
536
  const heightUnit = cue.region.heightUnits == percentageUnit ? '%' : 'px';
504
537
  const widthUnit = cue.region.widthUnits == percentageUnit ? '%' : 'px';
@@ -631,4 +664,25 @@ shaka.text.UITextDisplayer = class {
631
664
 
632
665
  return (containerHeight * value / cue.cellResolution.rows) + 'px';
633
666
  }
667
+
668
+ /**
669
+ * Inherits a property from the parent Cue elements. If the value is falsy,
670
+ * it is assumed to be inherited from the parent. This returns null if the
671
+ * value isn't found.
672
+ *
673
+ * @param {!Array.<!shaka.extern.Cue>} parents
674
+ * @param {function(!shaka.extern.Cue):?T} cb
675
+ * @return {?T}
676
+ * @template T
677
+ * @private
678
+ */
679
+ static inheritProperty_(parents, cb) {
680
+ for (let i = parents.length - 1; i >= 0; i--) {
681
+ const val = cb(parents[i]);
682
+ if (val || val === 0) {
683
+ return val;
684
+ }
685
+ }
686
+ return null;
687
+ }
634
688
  };