Source: lib/text/cue.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.text.Cue');
  7. goog.provide('shaka.text.CueRegion');
  8. goog.require('shaka.util.ArrayUtils');
  9. /**
  10. * @implements {shaka.extern.Cue}
  11. * @export
  12. */
  13. shaka.text.Cue = class {
  14. /**
  15. * @param {number} startTime
  16. * @param {number} endTime
  17. * @param {string} payload
  18. */
  19. constructor(startTime, endTime, payload) {
  20. const Cue = shaka.text.Cue;
  21. /**
  22. * @override
  23. * @exportInterface
  24. */
  25. this.startTime = startTime;
  26. /**
  27. * @override
  28. * @exportInterface
  29. */
  30. this.direction = Cue.direction.HORIZONTAL_LEFT_TO_RIGHT;
  31. /**
  32. * @override
  33. * @exportInterface
  34. */
  35. this.endTime = endTime;
  36. /**
  37. * @override
  38. * @exportInterface
  39. */
  40. this.payload = payload;
  41. /**
  42. * @override
  43. * @exportInterface
  44. */
  45. this.region = new shaka.text.CueRegion();
  46. /**
  47. * @override
  48. * @exportInterface
  49. */
  50. this.position = null;
  51. /**
  52. * @override
  53. * @exportInterface
  54. */
  55. this.positionAlign = Cue.positionAlign.AUTO;
  56. /**
  57. * @override
  58. * @exportInterface
  59. */
  60. this.size = 0;
  61. /**
  62. * @override
  63. * @exportInterface
  64. */
  65. this.textAlign = Cue.textAlign.CENTER;
  66. /**
  67. * @override
  68. * @exportInterface
  69. */
  70. this.writingMode = Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM;
  71. /**
  72. * @override
  73. * @exportInterface
  74. */
  75. this.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER;
  76. /**
  77. * @override
  78. * @exportInterface
  79. */
  80. this.line = null;
  81. /**
  82. * @override
  83. * @exportInterface
  84. */
  85. this.lineHeight = '';
  86. /**
  87. * Line Alignment is set to start by default.
  88. * @override
  89. * @exportInterface
  90. */
  91. this.lineAlign = Cue.lineAlign.START;
  92. /**
  93. * Set the captions at the bottom of the text container by default.
  94. * @override
  95. * @exportInterface
  96. */
  97. this.displayAlign = Cue.displayAlign.AFTER;
  98. /**
  99. * @override
  100. * @exportInterface
  101. */
  102. this.color = '';
  103. /**
  104. * @override
  105. * @exportInterface
  106. */
  107. this.backgroundColor = '';
  108. /**
  109. * @override
  110. * @exportInterface
  111. */
  112. this.backgroundImage = '';
  113. /**
  114. * @override
  115. * @exportInterface
  116. */
  117. this.border = '';
  118. /**
  119. * @override
  120. * @exportInterface
  121. */
  122. this.textShadow = '';
  123. /**
  124. * @override
  125. * @exportInterface
  126. */
  127. this.textStrokeColor = '';
  128. /**
  129. * @override
  130. * @exportInterface
  131. */
  132. this.textStrokeWidth = '';
  133. /**
  134. * @override
  135. * @exportInterface
  136. */
  137. this.fontSize = '';
  138. /**
  139. * @override
  140. * @exportInterface
  141. */
  142. this.fontWeight = Cue.fontWeight.NORMAL;
  143. /**
  144. * @override
  145. * @exportInterface
  146. */
  147. this.fontStyle = Cue.fontStyle.NORMAL;
  148. /**
  149. * @override
  150. * @exportInterface
  151. */
  152. this.fontFamily = '';
  153. /**
  154. * @override
  155. * @exportInterface
  156. */
  157. this.letterSpacing = '';
  158. /**
  159. * @override
  160. * @exportInterface
  161. */
  162. this.linePadding = '';
  163. /**
  164. * @override
  165. * @exportInterface
  166. */
  167. this.opacity = 1;
  168. /**
  169. * @override
  170. * @exportInterface
  171. */
  172. this.textDecoration = [];
  173. /**
  174. * @override
  175. * @exportInterface
  176. */
  177. this.wrapLine = true;
  178. /**
  179. * @override
  180. * @exportInterface
  181. */
  182. this.id = '';
  183. /**
  184. * @override
  185. * @exportInterface
  186. */
  187. this.nestedCues = [];
  188. /**
  189. * @override
  190. * @exportInterface
  191. */
  192. this.isContainer = false;
  193. /**
  194. * @override
  195. * @exportInterface
  196. */
  197. this.lineBreak = false;
  198. /**
  199. * @override
  200. * @exportInterface
  201. */
  202. this.spacer = false;
  203. /**
  204. * @override
  205. * @exportInterface
  206. */
  207. this.cellResolution = {
  208. columns: 32,
  209. rows: 15,
  210. };
  211. }
  212. /**
  213. * @param {number} start
  214. * @param {number} end
  215. * @return {!shaka.text.Cue}
  216. */
  217. static lineBreak(start, end) {
  218. const cue = new shaka.text.Cue(start, end, '');
  219. cue.lineBreak = true;
  220. return cue;
  221. }
  222. /**
  223. * Create a copy of the cue with the same properties.
  224. * @return {!shaka.text.Cue}
  225. * @suppress {checkTypes} since we must use [] and "in" with a struct type.
  226. */
  227. clone() {
  228. const clone = new shaka.text.Cue(0, 0, '');
  229. for (const k in this) {
  230. clone[k] = this[k];
  231. // Make copies of array fields, but only one level deep. That way, if we
  232. // change, for instance, textDecoration on the clone, we don't affect the
  233. // original.
  234. if (clone[k] && clone[k].constructor == Array) {
  235. clone[k] = /** @type {!Array} */(clone[k]).slice();
  236. }
  237. }
  238. return clone;
  239. }
  240. /**
  241. * Check if two Cues have all the same values in all properties.
  242. * @param {!shaka.text.Cue} cue1
  243. * @param {!shaka.text.Cue} cue2
  244. * @return {boolean}
  245. * @suppress {checkTypes} since we must use [] and "in" with a struct type.
  246. */
  247. static equal(cue1, cue2) {
  248. // Compare the start time, end time and payload of the cues first for
  249. // performance optimization. We can avoid the more expensive recursive
  250. // checks if the top-level properties don't match.
  251. // See: https://github.com/shaka-project/shaka-player/issues/3018
  252. if (cue1.startTime != cue2.startTime || cue1.endTime != cue2.endTime ||
  253. cue1.payload != cue2.payload) {
  254. return false;
  255. }
  256. for (const k in cue1) {
  257. if (k == 'startTime' || k == 'endTime' || k == 'payload') {
  258. // Already compared.
  259. } else if (k == 'nestedCues') {
  260. // This uses shaka.text.Cue.equal rather than just this.equal, since
  261. // otherwise recursing here will unbox the method and cause "this" to be
  262. // undefined in deeper recursion.
  263. if (!shaka.util.ArrayUtils.equal(
  264. cue1.nestedCues, cue2.nestedCues, shaka.text.Cue.equal)) {
  265. return false;
  266. }
  267. } else if (k == 'region' || k == 'cellResolution') {
  268. for (const k2 in cue1[k]) {
  269. if (cue1[k][k2] != cue2[k][k2]) {
  270. return false;
  271. }
  272. }
  273. } else if (Array.isArray(cue1[k])) {
  274. if (!shaka.util.ArrayUtils.equal(cue1[k], cue2[k])) {
  275. return false;
  276. }
  277. } else {
  278. if (cue1[k] != cue2[k]) {
  279. return false;
  280. }
  281. }
  282. }
  283. return true;
  284. }
  285. };
  286. /**
  287. * @enum {string}
  288. * @export
  289. */
  290. shaka.text.Cue.positionAlign = {
  291. 'LEFT': 'line-left',
  292. 'RIGHT': 'line-right',
  293. 'CENTER': 'center',
  294. 'AUTO': 'auto',
  295. };
  296. /**
  297. * @enum {string}
  298. * @export
  299. */
  300. shaka.text.Cue.textAlign = {
  301. 'LEFT': 'left',
  302. 'RIGHT': 'right',
  303. 'CENTER': 'center',
  304. 'START': 'start',
  305. 'END': 'end',
  306. };
  307. /**
  308. * Vertical alignments of the cues within their extents.
  309. * 'BEFORE' means displaying at the top of the captions container box, 'CENTER'
  310. * means in the middle, 'AFTER' means at the bottom.
  311. * @enum {string}
  312. * @export
  313. */
  314. shaka.text.Cue.displayAlign = {
  315. 'BEFORE': 'before',
  316. 'CENTER': 'center',
  317. 'AFTER': 'after',
  318. };
  319. /**
  320. * @enum {string}
  321. * @export
  322. */
  323. shaka.text.Cue.direction = {
  324. 'HORIZONTAL_LEFT_TO_RIGHT': 'ltr',
  325. 'HORIZONTAL_RIGHT_TO_LEFT': 'rtl',
  326. };
  327. /**
  328. * @enum {string}
  329. * @export
  330. */
  331. shaka.text.Cue.writingMode = {
  332. 'HORIZONTAL_TOP_TO_BOTTOM': 'horizontal-tb',
  333. 'VERTICAL_LEFT_TO_RIGHT': 'vertical-lr',
  334. 'VERTICAL_RIGHT_TO_LEFT': 'vertical-rl',
  335. };
  336. /**
  337. * @enum {number}
  338. * @export
  339. */
  340. shaka.text.Cue.lineInterpretation = {
  341. 'LINE_NUMBER': 0,
  342. 'PERCENTAGE': 1,
  343. };
  344. /**
  345. * @enum {string}
  346. * @export
  347. */
  348. shaka.text.Cue.lineAlign = {
  349. 'CENTER': 'center',
  350. 'START': 'start',
  351. 'END': 'end',
  352. };
  353. /**
  354. * Default text color according to
  355. * https://w3c.github.io/webvtt/#default-text-color
  356. * @enum {string}
  357. * @export
  358. */
  359. shaka.text.Cue.defaultTextColor = {
  360. 'white': '#FFF',
  361. 'lime': '#0F0',
  362. 'cyan': '#0FF',
  363. 'red': '#F00',
  364. 'yellow': '#FF0',
  365. 'magenta': '#F0F',
  366. 'blue': '#00F',
  367. 'black': '#000',
  368. };
  369. /**
  370. * Default text background color according to
  371. * https://w3c.github.io/webvtt/#default-text-background
  372. * @enum {string}
  373. * @export
  374. */
  375. shaka.text.Cue.defaultTextBackgroundColor = {
  376. 'bg_white': '#FFF',
  377. 'bg_lime': '#0F0',
  378. 'bg_cyan': '#0FF',
  379. 'bg_red': '#F00',
  380. 'bg_yellow': '#FF0',
  381. 'bg_magenta': '#F0F',
  382. 'bg_blue': '#00F',
  383. 'bg_black': '#000',
  384. };
  385. /**
  386. * In CSS font weight can be a number, where 400 is normal and 700 is bold.
  387. * Use these values for the enum for consistency.
  388. * @enum {number}
  389. * @export
  390. */
  391. shaka.text.Cue.fontWeight = {
  392. 'NORMAL': 400,
  393. 'BOLD': 700,
  394. };
  395. /**
  396. * @enum {string}
  397. * @export
  398. */
  399. shaka.text.Cue.fontStyle = {
  400. 'NORMAL': 'normal',
  401. 'ITALIC': 'italic',
  402. 'OBLIQUE': 'oblique',
  403. };
  404. /**
  405. * @enum {string}
  406. * @export
  407. */
  408. shaka.text.Cue.textDecoration = {
  409. 'UNDERLINE': 'underline',
  410. 'LINE_THROUGH': 'lineThrough',
  411. 'OVERLINE': 'overline',
  412. };
  413. /**
  414. * @implements {shaka.extern.CueRegion}
  415. * @struct
  416. * @export
  417. */
  418. shaka.text.CueRegion = class {
  419. /** */
  420. constructor() {
  421. const CueRegion = shaka.text.CueRegion;
  422. /**
  423. * @override
  424. * @exportInterface
  425. */
  426. this.id = '';
  427. /**
  428. * @override
  429. * @exportInterface
  430. */
  431. this.viewportAnchorX = 0;
  432. /**
  433. * @override
  434. * @exportInterface
  435. */
  436. this.viewportAnchorY = 0;
  437. /**
  438. * @override
  439. * @exportInterface
  440. */
  441. this.regionAnchorX = 0;
  442. /**
  443. * @override
  444. * @exportInterface
  445. */
  446. this.regionAnchorY = 0;
  447. /**
  448. * @override
  449. * @exportInterface
  450. */
  451. this.width = 100;
  452. /**
  453. * @override
  454. * @exportInterface
  455. */
  456. this.height = 100;
  457. /**
  458. * @override
  459. * @exportInterface
  460. */
  461. this.heightUnits = CueRegion.units.PERCENTAGE;
  462. /**
  463. * @override
  464. * @exportInterface
  465. */
  466. this.widthUnits = CueRegion.units.PERCENTAGE;
  467. /**
  468. * @override
  469. * @exportInterface
  470. */
  471. this.viewportAnchorUnits = CueRegion.units.PERCENTAGE;
  472. /**
  473. * @override
  474. * @exportInterface
  475. */
  476. this.scroll = CueRegion.scrollMode.NONE;
  477. }
  478. };
  479. /**
  480. * @enum {number}
  481. * @export
  482. */
  483. shaka.text.CueRegion.units = {
  484. 'PX': 0,
  485. 'PERCENTAGE': 1,
  486. 'LINES': 2,
  487. };
  488. /**
  489. * @enum {string}
  490. * @export
  491. */
  492. shaka.text.CueRegion.scrollMode = {
  493. 'NONE': '',
  494. 'UP': 'up',
  495. };