Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / media / encrypted-media / encrypted-media-utils.js
blob5a4f15afaf0c94d2e18c64457b4aa64ebd5ed960
1 var consoleDiv = null;
3 function consoleWrite(text)
5     if (!consoleDiv && document.body) {
6         consoleDiv = document.createElement('div');
7         document.body.appendChild(consoleDiv);
8     }
9     var span = document.createElement('span');
10     span.appendChild(document.createTextNode(text));
11     span.appendChild(document.createElement('br'));
12     consoleDiv.appendChild(span);
15 // Returns a promise that is fulfilled with true if |initDataType| is supported,
16 // or false if not.
17 function isInitDataTypeSupported(initDataType)
19     return navigator.requestMediaKeySystemAccess(
20                          "org.w3.clearkey", [{ initDataTypes : [initDataType] }])
21         .then(function() { return(true); }, function() { return(false); });
24 // Returns a promise that is fulfilled with an initDataType that is supported,
25 // rejected if none are supported.
26 function getSupportedInitDataType()
28     var configuration = [{ initDataTypes : [ 'webm', 'cenc', 'keyids' ] }];
29     return navigator.requestMediaKeySystemAccess('org.w3.clearkey', configuration)
30         .then(function(access) {
31             var initDataTypes = access.getConfiguration().initDataTypes;
32             assert_greater_than(initDataTypes.length, 0);
33             return Promise.resolve(initDataTypes[0]);
34         }, function(error) {
35             return Promise.reject('No supported initDataType.');
36         });
39 function getInitData(initDataType)
41   if (initDataType == 'webm') {
42       return new Uint8Array([
43           0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
44           0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
45       ]);
46   }
48   if (initDataType == 'cenc') {
49       return new Uint8Array([
50           0x00, 0x00, 0x00, 0x00,                          // size = 0
51           0x70, 0x73, 0x73, 0x68,                          // 'pssh'
52           0x01,                                            // version = 1
53           0x00, 0x00, 0x00,                                // flags
54           0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,  // Common SystemID
55           0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
56           0x00, 0x00, 0x00, 0x01,                          // key count
57           0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,  // key
58           0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
59           0x00, 0x00, 0x00, 0x00                           // datasize
60      ]);
61   }
63   if (initDataType == 'keyids') {
64       var keyId = new Uint8Array([
65           0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
66           0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
67       ]);
68       return stringToUint8Array(createKeyIDs(keyId));
69   }
71   throw 'initDataType ' + initDataType + ' not supported.';
74 function waitForEventAndRunStep(eventName, element, func, stepTest)
76     var eventCallback = function(event) {
77         if (func)
78             func(event);
79     }
80     if (stepTest)
81         eventCallback = stepTest.step_func(eventCallback);
83     element.addEventListener(eventName, eventCallback, true);
86 // Copied from LayoutTests/resources/js-test.js.
87 // See it for details of why this is necessary.
88 function asyncGC(callback)
90     GCController.collectAll();
91     setTimeout(callback, 0);
94 function createGCPromise()
96     // Run gc() as a promise.
97     return new Promise(
98         function(resolve, reject) {
99             asyncGC(resolve);
100         });
103 function delayToAllowEventProcessingPromise()
105     return new Promise(
106         function(resolve, reject) {
107             setTimeout(resolve, 0);
108         });
111 function stringToUint8Array(str)
113     var result = new Uint8Array(str.length);
114     for(var i = 0; i < str.length; i++) {
115         result[i] = str.charCodeAt(i);
116     }
117     return result;
120 function arrayBufferAsString(buffer)
122     // MediaKeySession.keyStatuses iterators return an ArrayBuffer,
123     // so convert it into a printable string.
124     return String.fromCharCode.apply(null, new Uint8Array(buffer));
127 function dumpKeyStatuses(keyStatuses)
129     consoleWrite("for (var entry of keyStatuses)");
130     for (var entry of keyStatuses) {
131         consoleWrite(arrayBufferAsString(entry[0]) + ", " + entry[1]);
132     }
133     consoleWrite("for (var key of keyStatuses.keys())");
134     for (var key of keyStatuses.keys()) {
135         consoleWrite(arrayBufferAsString(key));
136     }
137     consoleWrite("for (var value of keyStatuses.values())");
138     for (var value of keyStatuses.values()) {
139         consoleWrite(value);
140     }
141     consoleWrite("for (var entry of keyStatuses.entries())");
142     for (var entry of keyStatuses.entries()) {
143         consoleWrite(arrayBufferAsString(entry[0]) + ", " + entry[1]);
144     }
145     consoleWrite("keyStatuses.forEach()");
146     keyStatuses.forEach(function(value, key, map) {
147         consoleWrite(arrayBufferAsString(key) + ", " + value);
148     });
151 // Verify that |keyStatuses| contains just the keys in |keys.expected|
152 // and none of the keys in |keys.unexpected|. All keys should have status
153 // 'usable'. Example call: verifyKeyStatuses(mediaKeySession.keyStatuses,
154 // { expected: [key1], unexpected: [key2] });
155 function verifyKeyStatuses(keyStatuses, keys)
157     var expected = keys.expected || [];
158     var unexpected = keys.unexpected || [];
160     // |keyStatuses| should have same size as number of |keys.expected|.
161     assert_equals(keyStatuses.size, expected.length);
163     // All |keys.expected| should be found.
164     expected.map(function(key) {
165         assert_true(keyStatuses.has(key));
166         assert_equals(keyStatuses.get(key), 'usable');
167     });
169     // All |keys.unexpected| should not be found.
170     unexpected.map(function(key) {
171         assert_false(keyStatuses.has(key));
172         assert_equals(keyStatuses.get(key), undefined);
173     });
176 // Encodes |data| into base64url string. There is no '=' padding, and the
177 // characters '-' and '_' must be used instead of '+' and '/', respectively.
178 function base64urlEncode(data)
180     var result = btoa(String.fromCharCode.apply(null, data));
181     return result.replace(/=+$/g, '').replace(/\+/g, "-").replace(/\//g, "_");
184 // Decode |encoded| using base64url decoding.
185 function base64urlDecode(encoded)
187     return atob(encoded.replace(/\-/g, "+").replace(/\_/g, "/"));
190 // For Clear Key, the License Format is a JSON Web Key (JWK) Set, which contains
191 // a set of cryptographic keys represented by JSON. These helper functions help
192 // wrap raw keys into a JWK set.
193 // See:
194 // https://w3c.github.io/encrypted-media/#clear-key-license-format
195 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key
197 // Creates a JWK from raw key ID and key.
198 // |keyId| and |key| are expected to be ArrayBufferViews, not base64-encoded.
199 function createJWK(keyId, key)
201     var jwk = '{"kty":"oct","alg":"A128KW","kid":"';
202     jwk += base64urlEncode(keyId);
203     jwk += '","k":"';
204     jwk += base64urlEncode(key);
205     jwk += '"}';
206     return jwk;
209 // Creates a JWK Set from multiple JWKs.
210 function createJWKSet()
212     var jwkSet = '{"keys":[';
213     for (var i = 0; i < arguments.length; i++) {
214         if (i != 0)
215             jwkSet += ',';
216         jwkSet += arguments[i];
217     }
218     jwkSet += ']}';
219     return jwkSet;
222 // Clear Key can also support Key IDs Initialization Data.
223 // ref: http://w3c.github.io/encrypted-media/keyids-format.html
224 // Each parameter is expected to be a key id in an Uint8Array.
225 function createKeyIDs()
227     var keyIds = '{"kids":["';
228     for (var i = 0; i < arguments.length; i++) {
229         if (i != 0)
230             keyIds += '","';
231         keyIds += base64urlEncode(arguments[i]);
232     }
233     keyIds += '"]}';
234     return keyIds;
237 function forceTestFailureFromPromise(test, error, message)
239     // Promises convert exceptions into rejected Promises. Since there is
240     // currently no way to report a failed test in the test harness, errors
241     // are reported using force_timeout().
242     if (message)
243         consoleWrite(message + ': ' + error.message);
244     else if (error)
245         consoleWrite(error);
247     test.force_timeout();
248     test.done();
251 function extractSingleKeyIdFromMessage(message)
253     var json = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(message)));
254     // Decode the first element of 'kids'.
255     assert_equals(1, json.kids.length);
256     var decoded_key = base64urlDecode(json.kids[0]);
257     // Convert to an Uint8Array and return it.
258     return stringToUint8Array(decoded_key);
261 // Create a MediaKeys object for Clear Key with 1 session. KeyId and key
262 // required for the video are already known and provided. Returns a promise
263 // that resolves to the MediaKeys object created.
264 function createMediaKeys(keyId, key)
266     var mediaKeys;
267     var mediaKeySession;
268     var request = stringToUint8Array(createKeyIDs(keyId));
269     var jwkSet = stringToUint8Array(createJWKSet(createJWK(keyId, key)));
271     return navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{}]).then(function(access) {
272         return access.createMediaKeys();
273     }).then(function(result) {
274         mediaKeys = result;
275         mediaKeySession = mediaKeys.createSession();
276         return mediaKeySession.generateRequest('keyids', request);
277     }).then(function() {
278         return mediaKeySession.update(jwkSet);
279     }).then(function() {
280         return Promise.resolve(mediaKeys);
281     });
284 // Play the specified |content| on |video|. Returns a promise that is resolved
285 // after the video plays for |duration| seconds.
286 function playVideoAndWaitForTimeupdate(video, content, duration)
288     video.src = content;
289     video.play();
290     return new Promise(function(resolve) {
291         video.addEventListener('timeupdate', function listener(event) {
292             if (event.target.currentTime < duration)
293                 return;
294             video.removeEventListener(listener);
295             resolve('success');
296         });
297     });