Index: third_party/WebKit/LayoutTests/imported/wpt/encrypted-media/polyfill/edge-keystatuses.js |
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/encrypted-media/polyfill/edge-keystatuses.js b/third_party/WebKit/LayoutTests/imported/wpt/encrypted-media/polyfill/edge-keystatuses.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8861444591bbd8ec5c5e1e86ccad2d5c45adab39 |
--- /dev/null |
+++ b/third_party/WebKit/LayoutTests/imported/wpt/encrypted-media/polyfill/edge-keystatuses.js |
@@ -0,0 +1,144 @@ |
+(function() { |
+ |
+ // This polyfill fixes the following problems with Edge browser |
+ // (1) Various maplike methods for keystatuses are not supported or suported incorrectly |
+ // (2) Key Ids exposed in keystatuses are incorrect (byte swaps) |
+ if ( navigator.userAgent.toLowerCase().indexOf('edge') > -1 ) { |
+ /////////////////////////////////////////////////////////////////////////////////////////////// |
+ // The following function is the core of this JS patch. The rest of this file is infrastructure |
+ // required to enable this function |
+ /////////////////////////////////////////////////////////////////////////////////////////////// |
+ function _proxyKeyStatusesChange( event ) { |
+ this._keyStatuses.clear(); |
+ var keyStatuses = []; |
+ this._session.keyStatuses.forEach( function( keyId, status ) { |
+ var newKeyId = new Uint8Array( keyId ); |
+ |
+ function swap( arr, a, b ) { var t = arr[a]; arr[a] = arr[b]; arr[b] = t; } |
+ swap( newKeyId, 0, 3 ); |
+ swap( newKeyId, 1, 2 ); |
+ swap( newKeyId, 4, 5 ); |
+ swap( newKeyId, 6, 7 ); |
+ |
+ keyStatuses.push( { key: newKeyId, status: status, ord: arrayBufferAsString( newKeyId ) } ); |
+ }); |
+ |
+ function lexicographical( a, b ) { return a < b ? -1 : a === b ? 0 : +1; } |
+ function lexicographicalkey( a, b ) { return lexicographical( a.ord, b.ord ); } |
+ |
+ keyStatuses.sort( lexicographicalkey ).forEach( function( obj ) { |
+ this._keyStatuses._set( obj.key, obj.status ); |
+ }.bind( this ) ); |
+ |
+ this.dispatchEvent( event ); |
+ }; |
+ /////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+ // Override MediaKeys.createSession |
+ var _mediaKeysCreateSession = MediaKeys.prototype.createSession; |
+ MediaKeys.prototype.createSession = function ( sessionType ) { |
+ return new MediaKeySession( _mediaKeysCreateSession.call( this, sessionType ) ); |
+ }; |
+ |
+ // MediaKeySession proxy |
+ function MediaKeySession( session ) { |
+ EventTarget.call( this ); |
+ this._session = session; |
+ this._keyStatuses = new MediaKeyStatusMap(); |
+ this._session.addEventListener("keystatuseschange",this._onKeyStatusesChange.bind(this)); |
+ this._session.addEventListener("message",this.dispatchEvent.bind(this)); |
+ } |
+ |
+ MediaKeySession.prototype = Object.create( EventTarget.prototype ); |
+ |
+ Object.defineProperties( MediaKeySession.prototype, { |
+ sessionId: { get: function() { return this._session.sessionId; } }, |
+ expiration: { get: function() { return this._session.expiration; } }, |
+ closed: { get: function() { return this._session.closed; } }, |
+ keyStatuses:{ get: function() { return this._keyStatuses; } } |
+ }); |
+ |
+ [ "generateRequest", "load", "update", "remove", "close" ].forEach( function( fnname ) { |
+ MediaKeySession.prototype[ fnname ] = function() { |
+ return window.MediaKeySession.prototype[ fnname ].apply( this._session, arguments ); |
+ } |
+ } ); |
+ |
+ MediaKeySession.prototype._onKeyStatusesChange = _proxyKeyStatusesChange; |
+ |
+ // MediaKeyStatusMap proxy |
+ // |
+ // We need a proxy class to replace the broken MediaKeyStatusMap one. We cannot use a |
+ // regular Map directly because we need get and has methods to compare by value not |
+ // as references. |
+ function MediaKeyStatusMap() { this._map = new Map(); } |
+ |
+ Object.defineProperties( MediaKeyStatusMap.prototype, { |
+ size: { get: function() { return this._map.size; } }, |
+ forEach: { get: function() { return function( f ) { return this._map.forEach( f ); } } }, |
+ entries: { get: function() { return function() { return this._map.entries(); } } }, |
+ values: { get: function() { return function() { return this._map.values(); } } }, |
+ keys: { get: function() { return function() { return this._map.keys(); } } }, |
+ clear: { get: function() { return function() { return this._map.clear(); } } } } ); |
+ |
+ MediaKeyStatusMap.prototype[ Symbol.iterator ] = function() { return this._map[ Symbol.iterator ]() }; |
+ |
+ MediaKeyStatusMap.prototype.has = function has( keyId ) { |
+ for ( var k of this._map.keys() ) { if ( arrayBufferEqual( k, keyId ) ) return true; } |
+ return false; |
+ }; |
+ |
+ MediaKeyStatusMap.prototype.get = function get( keyId ) { |
+ for ( var k of this._map.entries() ) { if ( arrayBufferEqual( k[ 0 ], keyId ) ) return k[ 1 ]; } |
+ }; |
+ |
+ MediaKeyStatusMap.prototype._set = function _set( keyId, status ) { |
+ this._map.set( new Uint8Array( keyId ), status ); |
+ }; |
+ |
+ function arrayBufferEqual(buf1, buf2) |
+ { |
+ if (buf1.byteLength !== buf2.byteLength) return false; |
+ var a1 = Array.from( new Int8Array(buf1) ), a2 = Array.from( new Int8Array(buf2) ); |
+ return a1.every( function( x, i ) { return x === a2[i]; } ); |
+ } |
+ |
+ // EventTarget |
+ function EventTarget(){ |
+ this.listeners = {}; |
+ }; |
+ |
+ EventTarget.prototype.listeners = null; |
+ |
+ EventTarget.prototype.addEventListener = function(type, callback){ |
+ if(!(type in this.listeners)) { |
+ this.listeners[type] = []; |
+ } |
+ this.listeners[type].push(callback); |
+ }; |
+ |
+ EventTarget.prototype.removeEventListener = function(type, callback){ |
+ if(!(type in this.listeners)) { |
+ return; |
+ } |
+ var stack = this.listeners[type]; |
+ for(var i = 0, l = stack.length; i < l; i++){ |
+ if(stack[i] === callback){ |
+ stack.splice(i, 1); |
+ return this.removeEventListener(type, callback); |
+ } |
+ } |
+ }; |
+ |
+ EventTarget.prototype.dispatchEvent = function(event){ |
+ if(!(event.type in this.listeners)) { |
+ return; |
+ } |
+ var stack = this.listeners[event.type]; |
+ event.target = this; |
+ for(var i = 0, l = stack.length; i < l; i++) { |
+ stack[i].call(this, event); |
+ } |
+ }; |
+ } |
+})(); |