OLD | NEW |
(Empty) | |
| 1 (function() { |
| 2 |
| 3 // This polyfill fixes the following problems with Edge browser |
| 4 // (1) Various maplike methods for keystatuses are not supported or suported
incorrectly |
| 5 // (2) Key Ids exposed in keystatuses are incorrect (byte swaps) |
| 6 if ( navigator.userAgent.toLowerCase().indexOf('edge') > -1 ) { |
| 7 ////////////////////////////////////////////////////////////////////////
/////////////////////// |
| 8 // The following function is the core of this JS patch. The rest of this
file is infrastructure |
| 9 // required to enable this function |
| 10 ////////////////////////////////////////////////////////////////////////
/////////////////////// |
| 11 function _proxyKeyStatusesChange( event ) { |
| 12 this._keyStatuses.clear(); |
| 13 var keyStatuses = []; |
| 14 this._session.keyStatuses.forEach( function( keyId, status ) { |
| 15 var newKeyId = new Uint8Array( keyId ); |
| 16 |
| 17 function swap( arr, a, b ) { var t = arr[a]; arr[a] = arr[b]; ar
r[b] = t; } |
| 18 swap( newKeyId, 0, 3 ); |
| 19 swap( newKeyId, 1, 2 ); |
| 20 swap( newKeyId, 4, 5 ); |
| 21 swap( newKeyId, 6, 7 ); |
| 22 |
| 23 keyStatuses.push( { key: newKeyId, status: status, ord: arrayBuf
ferAsString( newKeyId ) } ); |
| 24 }); |
| 25 |
| 26 function lexicographical( a, b ) { return a < b ? -1 : a === b ? 0 :
+1; } |
| 27 function lexicographicalkey( a, b ) { return lexicographical( a.ord,
b.ord ); } |
| 28 |
| 29 keyStatuses.sort( lexicographicalkey ).forEach( function( obj ) { |
| 30 this._keyStatuses._set( obj.key, obj.status ); |
| 31 }.bind( this ) ); |
| 32 |
| 33 this.dispatchEvent( event ); |
| 34 }; |
| 35 ////////////////////////////////////////////////////////////////////////
/////////////////////// |
| 36 |
| 37 // Override MediaKeys.createSession |
| 38 var _mediaKeysCreateSession = MediaKeys.prototype.createSession; |
| 39 MediaKeys.prototype.createSession = function ( sessionType ) { |
| 40 return new MediaKeySession( _mediaKeysCreateSession.call( this, sess
ionType ) ); |
| 41 }; |
| 42 |
| 43 // MediaKeySession proxy |
| 44 function MediaKeySession( session ) { |
| 45 EventTarget.call( this ); |
| 46 this._session = session; |
| 47 this._keyStatuses = new MediaKeyStatusMap(); |
| 48 this._session.addEventListener("keystatuseschange",this._onKeyStatus
esChange.bind(this)); |
| 49 this._session.addEventListener("message",this.dispatchEvent.bind(thi
s)); |
| 50 } |
| 51 |
| 52 MediaKeySession.prototype = Object.create( EventTarget.prototype ); |
| 53 |
| 54 Object.defineProperties( MediaKeySession.prototype, { |
| 55 sessionId: { get: function() { return this._session.sessionId; } }, |
| 56 expiration: { get: function() { return this._session.expiration; } }
, |
| 57 closed: { get: function() { return this._session.closed; } }, |
| 58 keyStatuses:{ get: function() { return this._keyStatuses; } } |
| 59 }); |
| 60 |
| 61 [ "generateRequest", "load", "update", "remove", "close" ].forEach( func
tion( fnname ) { |
| 62 MediaKeySession.prototype[ fnname ] = function() { |
| 63 return window.MediaKeySession.prototype[ fnname ].apply( this._s
ession, arguments ); |
| 64 } |
| 65 } ); |
| 66 |
| 67 MediaKeySession.prototype._onKeyStatusesChange = _proxyKeyStatusesChange
; |
| 68 |
| 69 // MediaKeyStatusMap proxy |
| 70 // |
| 71 // We need a proxy class to replace the broken MediaKeyStatusMap one. We
cannot use a |
| 72 // regular Map directly because we need get and has methods to compare b
y value not |
| 73 // as references. |
| 74 function MediaKeyStatusMap() { this._map = new Map(); } |
| 75 |
| 76 Object.defineProperties( MediaKeyStatusMap.prototype, { |
| 77 size: { get: function() { return this._map.size; } }, |
| 78 forEach: { get: function() { return function( f ) { retur
n this._map.forEach( f ); } } }, |
| 79 entries: { get: function() { return function() { return t
his._map.entries(); } } }, |
| 80 values: { get: function() { return function() { return t
his._map.values(); } } }, |
| 81 keys: { get: function() { return function() { return t
his._map.keys(); } } }, |
| 82 clear: { get: function() { return function() { return t
his._map.clear(); } } } } ); |
| 83 |
| 84 MediaKeyStatusMap.prototype[ Symbol.iterator ] = function() { return thi
s._map[ Symbol.iterator ]() }; |
| 85 |
| 86 MediaKeyStatusMap.prototype.has = function has( keyId ) { |
| 87 for ( var k of this._map.keys() ) { if ( arrayBufferEqual( k, keyId
) ) return true; } |
| 88 return false; |
| 89 }; |
| 90 |
| 91 MediaKeyStatusMap.prototype.get = function get( keyId ) { |
| 92 for ( var k of this._map.entries() ) { if ( arrayBufferEqual( k[ 0 ]
, keyId ) ) return k[ 1 ]; } |
| 93 }; |
| 94 |
| 95 MediaKeyStatusMap.prototype._set = function _set( keyId, status ) { |
| 96 this._map.set( new Uint8Array( keyId ), status ); |
| 97 }; |
| 98 |
| 99 function arrayBufferEqual(buf1, buf2) |
| 100 { |
| 101 if (buf1.byteLength !== buf2.byteLength) return false; |
| 102 var a1 = Array.from( new Int8Array(buf1) ), a2 = Array.from( new Int
8Array(buf2) ); |
| 103 return a1.every( function( x, i ) { return x === a2[i]; } ); |
| 104 } |
| 105 |
| 106 // EventTarget |
| 107 function EventTarget(){ |
| 108 this.listeners = {}; |
| 109 }; |
| 110 |
| 111 EventTarget.prototype.listeners = null; |
| 112 |
| 113 EventTarget.prototype.addEventListener = function(type, callback){ |
| 114 if(!(type in this.listeners)) { |
| 115 this.listeners[type] = []; |
| 116 } |
| 117 this.listeners[type].push(callback); |
| 118 }; |
| 119 |
| 120 EventTarget.prototype.removeEventListener = function(type, callback){ |
| 121 if(!(type in this.listeners)) { |
| 122 return; |
| 123 } |
| 124 var stack = this.listeners[type]; |
| 125 for(var i = 0, l = stack.length; i < l; i++){ |
| 126 if(stack[i] === callback){ |
| 127 stack.splice(i, 1); |
| 128 return this.removeEventListener(type, callback); |
| 129 } |
| 130 } |
| 131 }; |
| 132 |
| 133 EventTarget.prototype.dispatchEvent = function(event){ |
| 134 if(!(event.type in this.listeners)) { |
| 135 return; |
| 136 } |
| 137 var stack = this.listeners[event.type]; |
| 138 event.target = this; |
| 139 for(var i = 0, l = stack.length; i < l; i++) { |
| 140 stack[i].call(this, event); |
| 141 } |
| 142 }; |
| 143 } |
| 144 })(); |
OLD | NEW |