diff --git a/lib/util/string_utils.js b/lib/util/string_utils.js index bd56d9be53..a360b16932 100644 --- a/lib/util/string_utils.js +++ b/lib/util/string_utils.js @@ -17,6 +17,7 @@ goog.provide('shaka.util.StringUtils'); +goog.require('goog.asserts'); goog.require('shaka.log'); goog.require('shaka.util.Error'); @@ -217,13 +218,48 @@ shaka.util.StringUtils = class { * @return {string} */ static fromCharCode(array) { - const max = 16000; - let ret = ''; - for (let i = 0; i < array.length; i += max) { - const subArray = array.subarray(i, i + max); - ret += String.fromCharCode(...subArray); + // Check the browser for what chunk sizes it supports. Cache the result + // in an impl method to avoid checking several times. + if (!shaka.util.StringUtils.fromCharCodeImpl_) { + const supportsChunkSize = (size) => { + try { + const buffer = new Uint8Array(size); + // The compiler will complain about suspicious value if this isn't + // stored in a variable and used. + const foo = String.fromCharCode(...buffer); + goog.asserts.assert(foo, 'Should get value'); + return true; + } catch (error) { + return false; + } + }; + + // Different browsers support different chunk sizes; find out the largest + // this browser supports so we can use larger chunks on supported browsers + // but still support lower-end devices that require small chunks. + // 64k is supported on all major desktop browsers. + for (let size = 64 * 1024; size > 0; size /= 2) { + if (supportsChunkSize(size)) { + shaka.util.StringUtils.fromCharCodeImpl_ = (buffer) => { + let ret = ''; + for (let i = 0; i < buffer.length; i += size) { + const subArray = buffer.subarray(i, i + size); + ret += String.fromCharCode(...subArray); + } + return ret; + }; + break; + } + } } - return ret; + goog.asserts.assert( + shaka.util.StringUtils.fromCharCodeImpl_, + 'Unable to create a fromCharCode method'); + return shaka.util.StringUtils.fromCharCodeImpl_(array); } }; + + +/** @private {?function(!TypedArray):string} */ +shaka.util.StringUtils.fromCharCodeImpl_ = null;