diff --git a/AUTHORS b/AUTHORS index 2e60643b2..9c787fd2a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -50,6 +50,7 @@ SameGoal Inc. <*@samegoal.com> Sanborn Hilland Sander Saares TalkTalk Plc <*@talktalkplc.com> +Tatsiana Gelahova Tomas Tichy Tomohiro Matsuzawa Toshihiro Suzuki diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 75a9e91fd..d7e35271b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -76,6 +76,7 @@ Sandra Lokshina Satheesh Velmurugan Semih Gokceoglu Seth Madison +Tatsiana Gelahova Theodore Abshire Thomas Stephens Tim Plummer diff --git a/externs/shaka/text.js b/externs/shaka/text.js index df9a77f9c..1db8924e4 100644 --- a/externs/shaka/text.js +++ b/externs/shaka/text.js @@ -246,6 +246,15 @@ shaka.extern.Cue = class { */ this.backgroundColor; + /** + * The number of horizontal and vertical cells into which + * the Root Container Region area is divided + * + * @type {{ columns: number, rows: number }} + * @exportDoc + */ + this.cellResolution; + /** * Image background represented by any string that would be * accepted in image HTML element. diff --git a/lib/text/cue.js b/lib/text/cue.js index 06ba0c925..db7495b5a 100644 --- a/lib/text/cue.js +++ b/lib/text/cue.js @@ -200,6 +200,15 @@ shaka.text.Cue = class { * @exportInterface */ this.spacer = false; + + /** + * @override + * @exportInterface + */ + this.cellResolution = { + columns: 32, + rows: 15, + }; } }; diff --git a/lib/text/ttml_text_parser.js b/lib/text/ttml_text_parser.js index 69a682b28..c23851c42 100644 --- a/lib/text/ttml_text_parser.js +++ b/lib/text/ttml_text_parser.js @@ -76,6 +76,7 @@ shaka.text.TtmlTextParser = class { let tickRate = null; let spaceStyle = null; let extent = null; + let cellResolution = null; const tts = xml.getElementsByTagName('tt'); const tt = tts[0]; // TTML should always have tt element. @@ -91,6 +92,7 @@ shaka.text.TtmlTextParser = class { frameRateMultiplier = XmlUtils.getAttributeNS(tt, ttpNs, 'frameRateMultiplier'); tickRate = XmlUtils.getAttributeNS(tt, ttpNs, 'tickRate'); + cellResolution = XmlUtils.getAttributeNS(tt, ttpNs, 'cellResolution'); spaceStyle = tt.getAttribute('xml:space') || 'default'; extent = tt.getAttribute('tts:extent'); } @@ -107,6 +109,9 @@ shaka.text.TtmlTextParser = class { const rateInfo = new TtmlTextParser.RateInfo_( frameRate, subFrameRate, frameRateMultiplier, tickRate); + const cellResolutionInfo = + TtmlTextParser.getCellResolution_(cellResolution); + const metadataElements = TtmlTextParser.getLeafNodes_( tt.getElementsByTagName('metadata')[0]); const styles = TtmlTextParser.getLeafNodes_( @@ -127,7 +132,8 @@ shaka.text.TtmlTextParser = class { for (const node of textNodes) { const cue = TtmlTextParser.parseCue_( node, time.periodStart, rateInfo, metadataElements, styles, - regionElements, cueRegions, whitespaceTrim, false); + regionElements, cueRegions, whitespaceTrim, false, + cellResolutionInfo); if (cue) { ret.push(cue); } @@ -239,12 +245,13 @@ shaka.text.TtmlTextParser = class { * @param {!Array.} cueRegions * @param {boolean} whitespaceTrim * @param {boolean} isNested + * @param {?{columns: number, rows: number}} cellResolution * @return {shaka.text.Cue} * @private */ static parseCue_( cueElement, offset, rateInfo, metadataElements, styles, regionElements, - cueRegions, whitespaceTrim, isNested) { + cueRegions, whitespaceTrim, isNested, cellResolution) { if (isNested && cueElement.nodeName == 'br') { const cue = new shaka.text.Cue(0, 0, ''); cue.spacer = true; @@ -322,7 +329,8 @@ shaka.text.TtmlTextParser = class { regionElements, cueRegions, whitespaceTrim, - /* isNested= */ true + /* isNested= */ true, + cellResolution, ); if (nestedCue) { @@ -334,6 +342,10 @@ shaka.text.TtmlTextParser = class { const cue = new shaka.text.Cue(start, end, payload); cue.nestedCues = nestedCues; + if (cellResolution) { + cue.cellResolution = cellResolution; + } + // Get other properties if available. const regionElement = shaka.text.TtmlTextParser.getElementsFromCollection_( cueElement, 'region', regionElements, /* prefix= */ '')[0]; @@ -543,7 +555,12 @@ shaka.text.TtmlTextParser = class { const fontSize = TtmlTextParser.getStyleAttribute_( cueElement, region, styles, 'fontSize'); - if (fontSize && fontSize.match(TtmlTextParser.unitValues_)) { + + const isValidFontSizeUnit = fontSize + && (fontSize.match(TtmlTextParser.unitValues_) + || fontSize.match(TtmlTextParser.percentValue_)); + + if (isValidFontSizeUnit) { cue.fontSize = fontSize; } @@ -933,6 +950,31 @@ shaka.text.TtmlTextParser = class { return (milliseconds / 1000) + seconds + (minutes * 60) + (hours * 3600); } + + /** + * If ttp:cellResolution provided returns cell resolution info + * with number of columns and rows into which the Root Container + * Region area is divided + * + * @param {?string} cellResolution + * @return {?{columns: number, rows: number}} + * @private + */ + static getCellResolution_(cellResolution) { + if (!cellResolution) { + return null; + } + const matches = /^(\d+) (\d+)$/.exec(cellResolution); + + if (!matches) { + return null; + } + + const columns = parseInt(matches[1], 10); + const rows = parseInt(matches[2], 10); + + return {columns, rows}; + } }; /** @@ -996,9 +1038,16 @@ shaka.text.TtmlTextParser.percentValues_ = /** * @const * @private {!RegExp} - * @example 100px + * @example 0.6% 90% */ -shaka.text.TtmlTextParser.unitValues_ = /^(\d+px|\d+em)$/; +shaka.text.TtmlTextParser.percentValue_ = /^(\d{1,2}(?:\.\d+)?|100)%$/; + +/** + * @const + * @private {!RegExp} + * @example 100px, 8em, 0.80c + */ +shaka.text.TtmlTextParser.unitValues_ = /^(\d+px|\d+em|\d*\.?\d+c)$/; /** * @const diff --git a/test/text/ttml_text_parser_unit.js b/test/text/ttml_text_parser_unit.js index 729e11c60..44c943a2b 100644 --- a/test/text/ttml_text_parser_unit.js +++ b/test/text/ttml_text_parser_unit.js @@ -792,8 +792,8 @@ describe('TtmlTextParser', () => { verifyHelper( [ { - startTime: 62.05, - endTime: 3723.2, + startTime: 1, + endTime: 2, payload: 'Test', color: 'red', backgroundColor: 'blue', @@ -803,6 +803,12 @@ describe('TtmlTextParser', () => { lineHeight: '20px', fontSize: '10em', }, + { + startTime: 2, + endTime: 4, + payload: 'Test 2', + fontSize: '0.80c', + }, ], '' + '' + @@ -813,12 +819,14 @@ describe('TtmlTextParser', () => { 'tts:fontStyle="italic" ' + 'tts:lineHeight="20px" ' + 'tts:fontSize="10em"/>' + + '