@@ -127,7 +127,7 @@ shaka.text.TtmlTextParser.prototype.parseMedia = function(data, time) {
127127 }
128128 }
129129
130- let textNodes = TtmlTextParser . getLeafNodes_ (
130+ let textNodes = TtmlTextParser . getLeafCues_ (
131131 tt . getElementsByTagName ( 'body' ) [ 0 ] ) ;
132132
133133 for ( let i = 0 ; i < textNodes . length ; i ++ ) {
@@ -268,7 +268,10 @@ shaka.text.TtmlTextParser.getLeafNodes_ = function(element) {
268268 for ( let i = 0 ; i < childNodes . length ; i ++ ) {
269269 const childNodeItem = childNodes [ i ] ;
270270
271- if ( childNodeItem . nodeType == Node . ELEMENT_NODE && childNodeItem . nodeName !== 'br' ) {
271+ if (
272+ childNodeItem . nodeType == Node . ELEMENT_NODE &&
273+ childNodeItem . nodeName !== 'br'
274+ ) {
272275 // Get the leaves the child might contain.
273276 goog . asserts . assert ( childNodeItem instanceof Element ,
274277 'Node should be Element!' ) ;
@@ -277,23 +280,7 @@ shaka.text.TtmlTextParser.getLeafNodes_ = function(element) {
277280 goog . asserts . assert ( leafChildren . length > 0 ,
278281 'Only a null Element should return no leaves!' ) ;
279282
280- const nearestAncestor = element . hasAttribute ( 'begin' ) ? element : element . closest ( '[begin]' ) ;
281-
282- if ( nearestAncestor ) {
283- const begin = nearestAncestor . getAttribute ( 'begin' ) ;
284- const end = nearestAncestor . getAttribute ( 'end' ) ;
285- const region = nearestAncestor . getAttribute ( 'region' ) ;
286-
287- result = result . concat ( leafChildren . map ( leafChild => {
288- leafChild . setAttribute ( 'begin' , begin ) ;
289- leafChild . setAttribute ( 'end' , end ) ;
290- leafChild . setAttribute ( 'region' , leafChild . getAttribute ( 'region' ) || region ) ;
291-
292- return leafChild ;
293- } ) ) ;
294- } else {
295- result = result . concat ( leafChildren ) ;
296- }
283+ result = result . concat ( leafChildren ) ;
297284 }
298285 }
299286
@@ -305,31 +292,20 @@ shaka.text.TtmlTextParser.getLeafNodes_ = function(element) {
305292 return result ;
306293} ;
307294
295+ shaka . text . TtmlTextParser . getLeafCues_ = function ( element ) {
296+ if ( ! element ) {
297+ return [ ] ;
298+ }
308299
309- /**
310- * Inserts \n where <br> tags are found.
311- *
312- * @param {!Node } element
313- * @param {boolean } whitespaceTrim
314- * @private
315- */
316- shaka . text . TtmlTextParser . addNewLines_ = function ( element , whitespaceTrim ) {
317- let childNodes = element . childNodes ;
300+ return Array . from ( element . querySelectorAll ( '[begin][end]' ) ) ;
301+ } ;
318302
319- for ( let i = 0 ; i < childNodes . length ; i ++ ) {
320- if ( childNodes [ i ] . nodeName == 'br' && i > 0 ) {
321- childNodes [ i - 1 ] . textContent += '\n' ;
322- } else if ( childNodes [ i ] . childNodes . length > 0 ) {
323- shaka . text . TtmlTextParser . addNewLines_ ( childNodes [ i ] , whitespaceTrim ) ;
324- } else if ( whitespaceTrim ) {
325- // Trim leading and trailing whitespace.
326- let trimmed = childNodes [ i ] . textContent . trim ( ) ;
327- // Collapse multiple spaces into one.
328- trimmed = trimmed . replace ( / \s + / g, ' ' ) ;
329-
330- childNodes [ i ] . textContent = trimmed ;
331- }
332- }
303+ shaka . text . TtmlTextParser . sanitizeTextContent = function ( textContent ) {
304+ return textContent
305+ // Trim leading and trailing whitespace.
306+ . trim ( )
307+ // Collapse multiple spaces into one.
308+ . replace ( / \s + / g, ' ' ) ;
333309} ;
334310
335311
@@ -349,33 +325,76 @@ shaka.text.TtmlTextParser.addNewLines_ = function(element, whitespaceTrim) {
349325 */
350326shaka . text . TtmlTextParser . parseCue_ = function (
351327 cueElement , offset , rateInfo , metadataElements , styles ,
352- regionElements , cueRegions , whitespaceTrim ) {
328+ regionElements , cueRegions , whitespaceTrim , isChild ) {
329+ if ( isChild && cueElement . nodeName === 'br' ) {
330+ const cue = new shaka . text . Cue ( ) ;
331+ cue . spacer = true ;
332+
333+ return cue ;
334+ }
335+
353336 // Disregard empty elements:
354337 // TTML allows for empty elements like <div></div>.
355338 // If cueElement has neither time attributes, nor
356339 // non-whitespace text, don't try to make a cue out of it.
357- if ( ! cueElement . hasAttribute ( 'begin' ) &&
358- ! cueElement . hasAttribute ( 'end' ) &&
359- / ^ \s * $ / . test ( cueElement . textContent ) ) {
340+ if (
341+ / ^ \s * $ / . test ( cueElement . textContent ) ||
342+ (
343+ ! isChild &&
344+ ! cueElement . hasAttribute ( 'begin' ) &&
345+ ! cueElement . hasAttribute ( 'end' )
346+ )
347+ ) {
360348 return null ;
361349 }
362350
363- shaka . text . TtmlTextParser . addNewLines_ ( cueElement , whitespaceTrim ) ;
364-
365351 // Get time.
366352 let start = shaka . text . TtmlTextParser . parseTime_ (
367353 cueElement . getAttribute ( 'begin' ) , rateInfo ) ;
368354 let end = shaka . text . TtmlTextParser . parseTime_ (
369355 cueElement . getAttribute ( 'end' ) , rateInfo ) ;
370356 let duration = shaka . text . TtmlTextParser . parseTime_ (
371357 cueElement . getAttribute ( 'dur' ) , rateInfo ) ;
372- let payload = cueElement . textContent ;
358+ let payload = '' ;
359+ let children = [ ] ;
360+
361+ if (
362+ cueElement . childNodes . length === 1 &&
363+ cueElement . childNodes [ 0 ] . nodeType === Node . TEXT_NODE
364+ ) {
365+ if ( whitespaceTrim ) {
366+ payload = shaka . text . TtmlTextParser . sanitizeTextContent (
367+ cueElement . textContent
368+ ) ;
369+ } else {
370+ payload = cueElement . textContent ;
371+ }
372+ } else {
373+ for ( let i = 0 ; i < cueElement . childNodes . length ; i ++ ) {
374+ const childNode = cueElement . childNodes [ i ] ;
375+ const childCue = shaka . text . TtmlTextParser . parseCue_ (
376+ childNode ,
377+ offset ,
378+ rateInfo ,
379+ metadataElements ,
380+ styles ,
381+ regionElements ,
382+ cueRegions ,
383+ whitespaceTrim ,
384+ true
385+ ) ;
386+
387+ if ( childCue ) {
388+ children . push ( childCue ) ;
389+ }
390+ }
391+ }
373392
374393 if ( end == null && duration != null ) {
375394 end = start + duration ;
376395 }
377396
378- if ( start == null || end == null ) {
397+ if ( ! isChild && ( start == null || end == null ) ) {
379398 throw new shaka . util . Error (
380399 shaka . util . Error . Severity . CRITICAL ,
381400 shaka . util . Error . Category . TEXT ,
@@ -386,9 +405,10 @@ shaka.text.TtmlTextParser.parseCue_ = function(
386405 end += offset ;
387406
388407 let cue = new shaka . text . Cue ( start , end , payload ) ;
408+ cue . children = children ;
389409
390410 // Get other properties if available.
391- let regionElement = shaka . text . TtmlTextParser . getElementFromCollection_ (
411+ const [ regionElement ] = shaka . text . TtmlTextParser . getElementFromCollection_ (
392412 cueElement , 'region' , regionElements , /* prefix= */ '' ) ;
393413 if ( regionElement && regionElement . getAttribute ( 'xml:id' ) ) {
394414 let regionId = regionElement . getAttribute ( 'xml:id' ) ;
@@ -397,7 +417,7 @@ shaka.text.TtmlTextParser.parseCue_ = function(
397417 } ) ;
398418 cue . region = regionsWithId [ 0 ] ;
399419 }
400- const imageElement = shaka . text . TtmlTextParser . getElementFromCollection_ (
420+ const [ imageElement ] = shaka . text . TtmlTextParser . getElementFromCollection_ (
401421 cueElement , 'smpte:backgroundImage' , metadataElements , '#' ) ;
402422 shaka . text . TtmlTextParser . addStyle_ (
403423 cue ,
@@ -701,6 +721,7 @@ shaka.text.TtmlTextParser.getStyleAttribute_ = function(
701721 // An attribute can be specified on region level or in a styling block
702722 // associated with the region or original element.
703723 const TtmlTextParser = shaka . text . TtmlTextParser ;
724+
704725 let attr = TtmlTextParser . getStyleAttributeFromElement_ (
705726 cueElement , styles , attribute ) ;
706727 if ( attr ) {
@@ -735,7 +756,7 @@ shaka.text.TtmlTextParser.getStyleAttributeFromRegion_ = function(
735756 }
736757 }
737758
738- let style = shaka . text . TtmlTextParser . getElementFromCollection_ (
759+ let [ style ] = shaka . text . TtmlTextParser . getElementFromCollection_ (
739760 region , 'style' , styles , /* prefix= */ '' ) ;
740761 if ( style ) {
741762 return XmlUtils . getAttributeNS ( style , ttsNs , attribute ) ;
@@ -759,14 +780,36 @@ shaka.text.TtmlTextParser.getStyleAttributeFromElement_ = function(
759780 const XmlUtils = shaka . util . XmlUtils ;
760781 const ttsNs = shaka . text . TtmlTextParser . styleNs_ ;
761782
762- let getElementFromCollection_ =
763- shaka . text . TtmlTextParser . getElementFromCollection_ ;
764- let style = getElementFromCollection_ (
783+ // Styling on elements should take precedence over the main styling attributes
784+ const elementAttribute = XmlUtils . getAttributeNS (
785+ cueElement ,
786+ ttsNs ,
787+ attribute
788+ ) ;
789+
790+ if ( elementAttribute ) {
791+ return elementAttribute ;
792+ }
793+
794+ const inheritedStyles = shaka . text . TtmlTextParser . getElementFromCollection_ (
765795 cueElement , 'style' , styles , /* prefix= */ '' ) ;
766- if ( style ) {
767- return XmlUtils . getAttributeNS ( style , ttsNs , attribute ) ;
796+
797+ let styleValue ;
798+
799+ // The last value in our styles stack takes the precedence over the others
800+ for ( let i = 0 ; i < inheritedStyles . length ; i ++ ) {
801+ const styleAttributeValue = XmlUtils . getAttributeNS (
802+ inheritedStyles [ i ] ,
803+ ttsNs ,
804+ attribute
805+ ) ;
806+
807+ if ( styleAttributeValue ) {
808+ styleValue = styleAttributeValue ;
809+ }
768810 }
769- return null ;
811+
812+ return styleValue ;
770813} ;
771814
772815
@@ -783,22 +826,31 @@ shaka.text.TtmlTextParser.getStyleAttributeFromElement_ = function(
783826 */
784827shaka . text . TtmlTextParser . getElementFromCollection_ = function (
785828 element , attributeName , collection , prefixName ) {
829+ const items = [ ] ;
830+
786831 if ( ! element || collection . length < 1 ) {
787- return null ;
832+ return items ;
788833 }
789- let item = null ;
790- let itemName = shaka . text . TtmlTextParser . getInheritedAttribute_ (
834+
835+ const attributeValue = shaka . text . TtmlTextParser . getInheritedAttribute_ (
791836 element , attributeName ) ;
792- if ( itemName ) {
793- for ( let i = 0 ; i < collection . length ; i ++ ) {
794- if ( ( prefixName + collection [ i ] . getAttribute ( 'xml:id' ) ) == itemName ) {
795- item = collection [ i ] ;
796- break ;
837+
838+ if ( attributeValue ) {
839+ // There could be multiple items in one attribute
840+ // <span style="style1 style2">A cue</span>
841+ const itemNames = attributeValue . split ( ' ' ) ;
842+
843+ itemNames . forEach ( ( itemName ) => {
844+ for ( let i = 0 ; i < collection . length ; i ++ ) {
845+ if ( ( prefixName + collection [ i ] . getAttribute ( 'xml:id' ) ) == itemName ) {
846+ items . push ( collection [ i ] ) ;
847+ break ;
848+ }
797849 }
798- }
850+ } ) ;
799851 }
800852
801- return item ;
853+ return items ;
802854} ;
803855
804856
0 commit comments