From 771619ff0ef8ba0e3da9569ded3894b428d03c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Velad=20Galv=C3=A1n?= Date: Tue, 25 Jan 2022 19:40:13 +0100 Subject: [PATCH] fix: Fix support for TTAF1 namespace (old version of TTML) (#3864) Fixes #3009 --- lib/text/ttml_text_parser.js | 33 ++++++++++++++++++------------ lib/util/xml_utils.js | 19 +++++++++++++++++ test/text/ttml_text_parser_unit.js | 27 ++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/lib/text/ttml_text_parser.js b/lib/text/ttml_text_parser.js index 7dedda641a..5f8b50de1c 100644 --- a/lib/text/ttml_text_parser.js +++ b/lib/text/ttml_text_parser.js @@ -86,16 +86,17 @@ shaka.text.TtmlTextParser = class { } // Get the framerate, subFrameRate and frameRateMultiplier if applicable. - const frameRate = XmlUtils.getAttributeNS(tt, ttpNs, 'frameRate'); - const subFrameRate = XmlUtils.getAttributeNS(tt, ttpNs, 'subFrameRate'); + const frameRate = XmlUtils.getAttributeNSList(tt, ttpNs, 'frameRate'); + const subFrameRate = XmlUtils.getAttributeNSList( + tt, ttpNs, 'subFrameRate'); const frameRateMultiplier = - XmlUtils.getAttributeNS(tt, ttpNs, 'frameRateMultiplier'); - const tickRate = XmlUtils.getAttributeNS(tt, ttpNs, 'tickRate'); + XmlUtils.getAttributeNSList(tt, ttpNs, 'frameRateMultiplier'); + const tickRate = XmlUtils.getAttributeNSList(tt, ttpNs, 'tickRate'); - const cellResolution = XmlUtils.getAttributeNS( + const cellResolution = XmlUtils.getAttributeNSList( tt, ttpNs, 'cellResolution'); const spaceStyle = tt.getAttribute('xml:space') || 'default'; - const extent = XmlUtils.getAttributeNS(tt, ttsNs, 'extent'); + const extent = XmlUtils.getAttributeNSList(tt, ttsNs, 'extent'); if (spaceStyle != 'default' && spaceStyle != 'preserve') { throw new shaka.util.Error( @@ -797,7 +798,7 @@ shaka.text.TtmlTextParser = class { return null; } - const attr = XmlUtils.getAttributeNS(region, ttsNs, attribute); + const attr = XmlUtils.getAttributeNSList(region, ttsNs, attribute); if (attr) { return attr; } @@ -822,7 +823,7 @@ shaka.text.TtmlTextParser = class { // Styling on elements should take precedence // over the main styling attributes - const elementAttribute = XmlUtils.getAttributeNS( + const elementAttribute = XmlUtils.getAttributeNSList( cueElement, ttsNs, attribute); @@ -865,7 +866,7 @@ shaka.text.TtmlTextParser = class { if (!styleAttributeValue) { // Fall back to tts namespace. - styleAttributeValue = XmlUtils.getAttributeNS( + styleAttributeValue = XmlUtils.getAttributeNSList( inheritedStyles[i], ttsNs, attribute); @@ -1320,20 +1321,26 @@ shaka.text.TtmlTextParser.textAlignToPositionAlign_ = { * document, not just "ttp:", so we use this with getAttributeNS() to ensure * that we support arbitrary namespace names. * - * @const {string} + * @const {!Array.} * @private */ -shaka.text.TtmlTextParser.parameterNs_ = 'http://www.w3.org/ns/ttml#parameter'; +shaka.text.TtmlTextParser.parameterNs_ = [ + 'http://www.w3.org/ns/ttml#parameter', + 'http://www.w3.org/2006/10/ttaf1#parameter', +]; /** * The namespace URL for TTML styles. Can be assigned any name in the TTML * document, not just "tts:", so we use this with getAttributeNS() to ensure * that we support arbitrary namespace names. * - * @const {string} + * @const {!Array.} * @private */ -shaka.text.TtmlTextParser.styleNs_ = 'http://www.w3.org/ns/ttml#styling'; +shaka.text.TtmlTextParser.styleNs_ = [ + 'http://www.w3.org/ns/ttml#styling', + 'http://www.w3.org/2006/10/ttaf1#styling', +]; /** * The namespace URL for EBU TTML styles. Can be assigned any name in the TTML diff --git a/lib/util/xml_utils.js b/lib/util/xml_utils.js index 1d9685f15b..84f4bf3cde 100644 --- a/lib/util/xml_utils.js +++ b/lib/util/xml_utils.js @@ -103,6 +103,25 @@ shaka.util.XmlUtils = class { } + /** + * Gets a namespace-qualified attribute. + * @param {!Element} elem The element to get from. + * @param {!Array.} nsList The lis of namespace URIs. + * @param {string} name The local name of the attribute. + * @return {?string} The attribute's value, or null if not present. + */ + static getAttributeNSList(elem, nsList, name) { + // Some browsers return the empty string when the attribute is missing, + // so check if it exists first. See: https://mzl.la/2L7F0UK + for (const ns of nsList) { + if (elem.hasAttributeNS(ns, name)) { + return elem.getAttributeNS(ns, name); + } + } + return null; + } + + /** * Gets the text contents of a node. * @param {!Node} elem The XML element. diff --git a/test/text/ttml_text_parser_unit.js b/test/text/ttml_text_parser_unit.js index fc81aed030..5355ffd104 100644 --- a/test/text/ttml_text_parser_unit.js +++ b/test/text/ttml_text_parser_unit.js @@ -1358,6 +1358,33 @@ describe('TtmlTextParser', () => { {startTime: 62.05, endTime: 3723.2}); }); + it('allows old-standard namespace', () => { + verifyHelper( + [ + { + startTime: 1, + endTime: 2, + payload: 'Test', + cellResolution: { + columns: 60, + rows: 20, + }, + fontSize: '67%', + }, + ], + '' + + '' + + '