<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[210555] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210555">210555</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2017-01-10 12:09:21 -0800 (Tue, 10 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Add support for MediaKeys.generateRequest().
https://bugs.webkit.org/show_bug.cgi?id=166880

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

Test: media/encrypted-media/mock-MediaKeySession-generateRequest.html

Implement MediaKeySession::generateRequest(). This requires some additions
to CDM, CDMPrivate, and CDMInstance to support platform adoption and to
implement mock support for testing. Additionally, add an InitDataRegistry
object which can sanitize and extract key data from various initData types.
(At the moment, only the &quot;keyids&quot; initData type is implemented.)

Drive-by fixes: Change all instances of initDataType from String -&gt; AtomicString.
Add &quot;const&quot; flags to all CDMPrivate methods that might be called from a const
reference.

* CMakeLists.txt:
* Modules/encryptedmedia/CDM.cpp:
(WebCore::CDM::supportsInitDataType):
(WebCore::CDM::sanitizeInitData):
(WebCore::CDM::supportsInitData):
* Modules/encryptedmedia/CDM.h:
* Modules/encryptedmedia/CDMInstance.h:
* Modules/encryptedmedia/CDMPrivate.h:
* Modules/encryptedmedia/InitDataRegistry.cpp: Added.
(WebCore::extractKeyIDsKeyids):
(WebCore::sanitizeKeyids):
(WebCore::sanitizeCenc):
(WebCore::extractKeyIDsCenc):
(WebCore::sanitizeWebM):
(WebCore::extractKeyIDsWebM):
(WebCore::InitDataRegistry::shared):
(WebCore::InitDataRegistry::InitDataRegistry):
(WebCore::InitDataRegistry::sanitizeInitData):
(WebCore::InitDataRegistry::extractKeyIDs):
(WebCore::InitDataRegistry::registerInitDataType):
* Modules/encryptedmedia/InitDataRegistry.h:
* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::messageEventName):
(WebCore::MediaKeySession::MediaKeySession):
(WebCore::MediaKeySession::generateRequest):
(WebCore::MediaKeySession::enqueueMessage):
* Modules/encryptedmedia/MediaKeySession.h:
* Modules/encryptedmedia/MediaKeys.cpp:
(WebCore::MediaKeys::setServerCertificate):
* WebCore.xcodeproj/project.pbxproj:
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMFactory::addKeysToSessionWithID):
(WebCore::MockCDMFactory::setSupportedDataTypes):
(WebCore::MockCDM::supportsInitDataType):
(WebCore::MockCDM::supportsConfiguration):
(WebCore::MockCDM::supportsConfigurationWithRestrictions):
(WebCore::MockCDM::supportsSessionTypeWithConfiguration):
(WebCore::MockCDM::supportsRobustness):
(WebCore::MockCDM::distinctiveIdentifiersRequirement):
(WebCore::MockCDM::persistentStateRequirement):
(WebCore::MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable):
(WebCore::MockCDM::supportsInitData):
(WebCore::MockCDMInstance::setServerCertificate):
(WebCore::MockCDMInstance::requestLicense):
* testing/MockCDMFactory.h:
(WebCore::MockCDMFactory::supportedDataTypes):
(WebCore::MockCDMFactory::hasSessionWithID):
(WebCore::MockCDMFactory::removeSessionWithID):
(WebCore::MockCDMFactory::setSupportedDataTypes): Deleted.

LayoutTests:

Add shouldResolve() and shouldReject() to video-test.js and update existing
tests to use these new functions.

* media/encrypted-media/mock-MediaKeys-createSession-expected.txt: Added.
* media/encrypted-media/mock-MediaKeys-createSession.html: Added.
* media/encrypted-media/mock-MediaKeys-setServerCertificate.html:
* media/encrypted-media/mock-MediaKeySession-generateRequest.html:
* media/encrypted-media/mock-MediaKeySystemAccess.html:
* media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html:
* media/video-test.js:
(shouldResolve):
(shouldReject):
* platform/mac/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsmediaencryptedmediamockMediaKeySystemAccesshtml">trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html</a></li>
<li><a href="#trunkLayoutTestsmediaencryptedmediamockMediaKeyscreateSessionhtml">trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html</a></li>
<li><a href="#trunkLayoutTestsmediaencryptedmediamockMediaKeyssetServerCertificatehtml">trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html</a></li>
<li><a href="#trunkLayoutTestsmediaencryptedmediamocknavigatorrequestMediaKeySystemAccesshtml">trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html</a></li>
<li><a href="#trunkLayoutTestsmediavideotestjs">trunk/LayoutTests/media/video-test.js</a></li>
<li><a href="#trunkLayoutTestsplatformmacTestExpectations">trunk/LayoutTests/platform/mac/TestExpectations</a></li>
<li><a href="#trunkSourceWebCoreCMakeListstxt">trunk/Source/WebCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaCDMcpp">trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaCDMh">trunk/Source/WebCore/Modules/encryptedmedia/CDM.h</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaCDMInstanceh">trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaCDMPrivateh">trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaMediaKeySessioncpp">trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaMediaKeySessionh">trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaMediaKeyscpp">trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCoretestingMockCDMFactorycpp">trunk/Source/WebCore/testing/MockCDMFactory.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingMockCDMFactoryh">trunk/Source/WebCore/testing/MockCDMFactory.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsmediaencryptedmediamockMediaKeySessiongenerateRequestexpectedtxt">trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediaencryptedmediamockMediaKeySessiongenerateRequesthtml">trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaInitDataRegistrycpp">trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesencryptedmediaInitDataRegistryh">trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/ChangeLog        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -1,5 +1,26 @@
</span><span class="cx"> 2017-01-10  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Add support for MediaKeys.generateRequest().
+        https://bugs.webkit.org/show_bug.cgi?id=166880
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Add shouldResolve() and shouldReject() to video-test.js and update existing
+        tests to use these new functions.
+
+        * media/encrypted-media/mock-MediaKeys-createSession-expected.txt: Added.
+        * media/encrypted-media/mock-MediaKeys-createSession.html: Added.
+        * media/encrypted-media/mock-MediaKeys-setServerCertificate.html:
+        * media/encrypted-media/mock-MediaKeySession-generateRequest.html:
+        * media/encrypted-media/mock-MediaKeySystemAccess.html:
+        * media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html:
+        * media/video-test.js:
+        (shouldResolve):
+        (shouldReject):
+        * platform/mac/TestExpectations:
+
+2017-01-10  Jer Noble  &lt;jer.noble@apple.com&gt;
+
</ins><span class="cx">         Add support for MediaKeys.createSession().
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=166796
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamockMediaKeySessiongenerateRequestexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt (0 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt                                (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest-expected.txt        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+RUN(internals.initializeMockMediaSource())
+RUN(mock = internals.registerMockCDM())
+RUN(mock.supportedDataTypes = [&quot;keyids&quot;])
+RUN(capabilities.initDataTypes = [&quot;keyids&quot;])
+RUN(capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs=&quot;mock&quot;' }] )
+RUN(promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities]))
+Promise resolved OK
+
+RUN(promise = mediaKeySystemAccess.createMediaKeys())
+Promise resolved OK
+
+Using an invalid initDataType string should reject.
+RUN(mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;))
+EXPECTED (typeof mediaKeySession == 'object') OK
+RUN(promise = mediaKeySession.generateRequest(&quot;invalid&quot;, stringToUInt8Array(&quot;invalid&quot;)))
+Promise rejected correctly OK
+
+Re-using a failed mediaKeySession should reject.
+RUN(kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot; ] }))
+RUN(promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids)))
+Promise rejected correctly OK
+
+Using a new mediaKeySession should resolve.
+RUN(kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot; ] }))
+RUN(mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;))
+RUN(promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids)))
+Promise resolved OK
+
+Using invalid initData should reject.
+RUN(kids = JSON.stringify({ invalid: &quot;invalid&quot; }))
+RUN(mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;))
+RUN(promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids)))
+Promise rejected correctly OK
+
+Using initData with extraneous information should resolve.
+RUN(kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot;], invalid: &quot;invalid&quot; }))
+RUN(mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;))
+RUN(promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids)))
+Promise resolved OK
+END OF TEST
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamockMediaKeySessiongenerateRequesthtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html (0 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html                                (rev 0)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySession-generateRequest.html        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -0,0 +1,109 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;script src=../video-test.js&gt;&lt;/script&gt;
+    &lt;script type=&quot;text/javascript&quot;&gt;
+    var mock;
+    var promise;
+    var mediaKeySystemAccess;
+    var mediaKeys;
+    var mediaKeySession;
+    var capabilities = {};
+    var kids;
+
+    function doTest()
+    {
+        if (!window.internals) {
+            failTest(&quot;Internals is required for this test.&quot;)
+            return;
+        }
+
+        run('internals.initializeMockMediaSource()');
+        run('mock = internals.registerMockCDM()');
+        run('mock.supportedDataTypes = [&quot;keyids&quot;]');
+        run('capabilities.initDataTypes = [&quot;keyids&quot;]');
+        run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs=&quot;mock&quot;' }] `);
+        run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
+    }
+
+    function next() {
+        if (!tests.length) {
+            mock.unregister();
+            endTest()
+            return;
+        }
+
+        var nextTest = tests.shift();
+        consoleWrite('');
+        nextTest();
+    }
+
+    function gotMediaKeySystemAccess(result) {
+        mediaKeySystemAccess = result;
+        next();
+    }
+
+    function gotMediaKeys(result) {
+        mediaKeys = result;
+        next();
+    }
+
+    function stringToUInt8Array(str)
+    {
+       var array = new Uint8Array(str.length);
+       for (var i=0; i&lt;str.length; i++)
+            array[i] = str.charCodeAt(i);
+       return array;
+    }
+
+    tests = [
+        function() {
+            run('promise = mediaKeySystemAccess.createMediaKeys()');
+            shouldResolve(promise).then(gotMediaKeys, failTest);
+        },
+
+        function() {
+            consoleWrite('Using an invalid initDataType string should reject.')
+            run('mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;)');
+            testExpected('typeof mediaKeySession', 'object')
+            run('promise = mediaKeySession.generateRequest(&quot;invalid&quot;, stringToUInt8Array(&quot;invalid&quot;))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Re-using a failed mediaKeySession should reject.')
+            run('kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot; ] })');
+            run('promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using a new mediaKeySession should resolve.')
+            run('kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot; ] })');
+            run('mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;)');
+            run('promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids))');
+            shouldResolve(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using invalid initData should reject.')
+            run('kids = JSON.stringify({ invalid: &quot;invalid&quot; })');
+            run('mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;)');
+            run('promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids))');
+            shouldReject(promise).then(next, next);
+        },
+
+        function() {
+            consoleWrite('Using initData with extraneous information should resolve.')
+            run('kids = JSON.stringify({ kids: [ &quot;MTIzNDU=&quot;], invalid: &quot;invalid&quot; })');
+            run('mediaKeySession = mediaKeys.createSession(&quot;temporary&quot;)');
+            run('promise = mediaKeySession.generateRequest(&quot;keyids&quot;, stringToUInt8Array(kids))');
+            shouldResolve(promise).then(next, next);
+        },
+    ];
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;doTest()&quot;&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamockMediaKeySystemAccesshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeySystemAccess.html        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -34,28 +34,7 @@
</span><span class="cx">         nextTest();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess =&gt; {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () =&gt; {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() =&gt; {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode =&gt; {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
</del><span class="cx">     function gotMediaKeySystemAccess(result) {
</span><del>-        logResult(Success, 'Promise resolved');
</del><span class="cx">         mediaKeySystemAccess = result;
</span><span class="cx">         next();
</span><span class="cx">     }
</span><span class="lines">@@ -65,18 +44,18 @@
</span><span class="cx">             run('capabilities.initDataTypes = [&quot;mock&quot;]');
</span><span class="cx">             run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs=&quot;mock&quot;' }] `);
</span><span class="cx">             run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
</span><del>-            promise.then(gotMediaKeySystemAccess).catch(failTest);
</del><ins>+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldResolve(promise);
</del><ins>+            shouldResolve(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('mock.canCreateInstances = false');
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="lines">@@ -83,18 +62,18 @@
</span><span class="cx">             run('mock.canCreateInstances = true');
</span><span class="cx">             run('capabilities.distinctiveIdentifier = &quot;not-allowed&quot;');
</span><span class="cx">             run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
</span><del>-            promise.then(gotMediaKeySystemAccess).catch(failTest);
</del><ins>+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldResolve(promise);
</del><ins>+            shouldResolve(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('mock.distinctiveIdentifiersRequirement = &quot;required&quot;');
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="lines">@@ -101,18 +80,18 @@
</span><span class="cx">             run('mock.distinctiveIdentifiersRequirement = &quot;optional&quot;');
</span><span class="cx">             run('capabilities.persistentState = &quot;not-allowed&quot;');
</span><span class="cx">             run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
</span><del>-            promise.then(gotMediaKeySystemAccess).catch(failTest);
</del><ins>+            shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldResolve(promise);
</del><ins>+            shouldResolve(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('mock.persistentStateRequirement = &quot;required&quot;');
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx">     ];
</span><span class="cx">     &lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamockMediaKeyscreateSessionhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-createSession.html        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx">         run('capabilities.initDataTypes = [&quot;mock&quot;]');
</span><span class="cx">         run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs=&quot;mock&quot;' }] `);
</span><span class="cx">         run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
</span><del>-        promise.then(gotMediaKeySystemAccess).catch(failTest);
</del><ins>+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function next() {
</span><span class="lines">@@ -38,34 +38,12 @@
</span><span class="cx">         nextTest();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess =&gt; {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () =&gt; {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() =&gt; {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode =&gt; {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
</del><span class="cx">     function gotMediaKeySystemAccess(result) {
</span><del>-        logResult(Success, 'Promise resolved');
</del><span class="cx">         mediaKeySystemAccess = result;
</span><span class="cx">         next();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function gotMediaKeys(result) {
</span><del>-        logResult(Success, 'Promise resolved');
</del><span class="cx">         mediaKeys = result;
</span><span class="cx">         next();
</span><span class="cx">     }
</span><span class="lines">@@ -81,7 +59,7 @@
</span><span class="cx">     tests = [
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            promise.then(gotMediaKeys).catch(failTest);
</del><ins>+            shouldResolve(promise).then(gotMediaKeys, failTest);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamockMediaKeyssetServerCertificatehtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-MediaKeys-setServerCertificate.html        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx">         run('capabilities.initDataTypes = [&quot;mock&quot;]');
</span><span class="cx">         run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs=&quot;mock&quot;' }] `);
</span><span class="cx">         run('promise = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, [capabilities])');
</span><del>-        promise.then(gotMediaKeySystemAccess).catch(failTest);
</del><ins>+        shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function next() {
</span><span class="lines">@@ -37,34 +37,12 @@
</span><span class="cx">         nextTest();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    function shouldResolve(promise) {
-        promise.then(mediaKeySystemAccess =&gt; {
-            logResult(Success, 'Promise resolved');
-            next();
-        }, () =&gt; {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
-    }
-
-    function shouldReject(promise) {
-        promise.then(() =&gt; {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode =&gt; {
-            logResult(Success, 'Promise rejected correctly');
-            next();
-        });
-    }
-
</del><span class="cx">     function gotMediaKeySystemAccess(result) {
</span><del>-        logResult(Success, 'Promise resolved');
</del><span class="cx">         mediaKeySystemAccess = result;
</span><span class="cx">         next();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function gotMediaKeys(result) {
</span><del>-        logResult(Success, 'Promise resolved');
</del><span class="cx">         mediaKeys = result;
</span><span class="cx">         next();
</span><span class="cx">     }
</span><span class="lines">@@ -80,28 +58,28 @@
</span><span class="cx">     tests = [
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeySystemAccess.createMediaKeys()');
</span><del>-            promise.then(gotMediaKeys).catch(failTest);
</del><ins>+            shouldResolve(promise).then(gotMediaKeys, failTest);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeys.setServerCertificate(new ArrayBuffer())');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array(&quot;invalid&quot;))');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array(&quot;valid&quot;))');
</span><del>-            shouldResolve(promise);
</del><ins>+            shouldResolve(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx"> 
</span><span class="cx">         function() {
</span><span class="cx">             run('mock.supportsServerCertificates = false');
</span><span class="cx">             run('promise = mediaKeys.setServerCertificate(stringToUInt8Array(&quot;valid&quot;))');
</span><del>-            shouldReject(promise);
</del><ins>+            shouldReject(promise).then(next, next);
</ins><span class="cx">         },
</span><span class="cx">     ];
</span><span class="cx">     &lt;/script&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsmediaencryptedmediamocknavigatorrequestMediaKeySystemAccesshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/encrypted-media/mock-navigator-requestMediaKeySystemAccess.html        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -34,27 +34,11 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function passingTestWithCapabilities(capabilities, success) {
</span><del>-        testWithCapabilities(capabilities);
-        promise.then(mediaKeySystemAccess =&gt; {
-            logResult(Success, 'Promise resolved');
-            success(mediaKeySystemAccess);
-            next();
-        }, () =&gt; {
-            logResult(Failed, 'Promise rejected');
-            next();
-        });
</del><ins>+        shouldResolve(testWithCapabilities(capabilities)).then(success).then(next, next);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function failingTestWithCapabilities(capabilities, failure) {
</span><del>-        testWithCapabilities(capabilities);
-        promise.then(() =&gt; {
-            logResult(Failed, 'Promise resolved incorrectly');
-            next();
-        }, exceptionCode =&gt; {
-            logResult(Success, 'Promise rejected correctly');
-            failure(exceptionCode)
-            next();
-        });
</del><ins>+        shouldReject(testWithCapabilities(capabilities)).then(failure).then(next, next);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function testWithCapabilities(capabilities) {
</span><span class="lines">@@ -61,6 +45,7 @@
</span><span class="cx">         window.capabilities = capabilities;
</span><span class="cx">         consoleWrite(`SET capabilities = '${ JSON.stringify(capabilities, null, 1) }'`);
</span><span class="cx">         run('promise  = navigator.requestMediaKeySystemAccess(&quot;org.webkit.mock&quot;, capabilities)');
</span><ins>+        return promise;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     tests = [
</span></span></pre></div>
<a id="trunkLayoutTestsmediavideotestjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/media/video-test.js (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/video-test.js        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/media/video-test.js        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -416,3 +416,28 @@
</span><span class="cx">             eventSender.mouseDown();
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+function shouldResolve(promise) {
+    return new Promise((resolve, reject) =&gt; {
+        promise.then(result =&gt; {
+            logResult(Success, 'Promise resolved');
+            resolve(result);
+        }).catch((error) =&gt; {
+            logResult(Failed, 'Promise rejected');
+            reject(error);
+        });
+    });
+}
+
+function shouldReject(promise) {
+    return new Promise((resolve, reject) =&gt; {
+        promise.then(result =&gt; {
+            logResult(Failed, 'Promise resolved incorrectly');
+            reject(result);
+        }).catch((error) =&gt; {
+            logResult(Success, 'Promise rejected correctly');
+            resolve(error);
+        });
+    });
+
+}
</ins></span></pre></div>
<a id="trunkLayoutTestsplatformmacTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/TestExpectations (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/TestExpectations        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/LayoutTests/platform/mac/TestExpectations        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -1469,6 +1469,7 @@
</span><span class="cx"> media/encrypted-media/mock-MediaKeySystemAccess.html [ Skip ]
</span><span class="cx"> media/encrypted-media/mock-MediaKeys-setServerCertificate.html [ Skip ]
</span><span class="cx"> media/encrypted-media/mock-MediaKeys-createSession.html [ Skip ]
</span><ins>+media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Skip ]
</ins><span class="cx"> 
</span><span class="cx"> webkit.org/b/166025 http/tests/fetch/fetching-same-resource-with-diffferent-options.html [ Pass Failure ]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/CMakeLists.txt (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/CMakeLists.txt        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/CMakeLists.txt        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -2982,6 +2982,7 @@
</span><span class="cx"> if (ENABLE_ENCRYPTED_MEDIA)
</span><span class="cx">     list(APPEND WebCore_SOURCES
</span><span class="cx">         Modules/encryptedmedia/CDM.cpp
</span><ins>+        Modules/encryptedmedia/InitDataRegistry.cpp
</ins><span class="cx">         Modules/encryptedmedia/MediaKeyMessageEvent.cpp
</span><span class="cx">         Modules/encryptedmedia/MediaKeySession.cpp
</span><span class="cx">         Modules/encryptedmedia/MediaKeyStatusMap.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/ChangeLog        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -1,5 +1,74 @@
</span><span class="cx"> 2017-01-10  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Add support for MediaKeys.generateRequest().
+        https://bugs.webkit.org/show_bug.cgi?id=166880
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Test: media/encrypted-media/mock-MediaKeySession-generateRequest.html
+
+        Implement MediaKeySession::generateRequest(). This requires some additions
+        to CDM, CDMPrivate, and CDMInstance to support platform adoption and to
+        implement mock support for testing. Additionally, add an InitDataRegistry
+        object which can sanitize and extract key data from various initData types.
+        (At the moment, only the &quot;keyids&quot; initData type is implemented.)
+
+        Drive-by fixes: Change all instances of initDataType from String -&gt; AtomicString.
+        Add &quot;const&quot; flags to all CDMPrivate methods that might be called from a const
+        reference.
+
+        * CMakeLists.txt:
+        * Modules/encryptedmedia/CDM.cpp:
+        (WebCore::CDM::supportsInitDataType):
+        (WebCore::CDM::sanitizeInitData):
+        (WebCore::CDM::supportsInitData):
+        * Modules/encryptedmedia/CDM.h:
+        * Modules/encryptedmedia/CDMInstance.h:
+        * Modules/encryptedmedia/CDMPrivate.h:
+        * Modules/encryptedmedia/InitDataRegistry.cpp: Added.
+        (WebCore::extractKeyIDsKeyids):
+        (WebCore::sanitizeKeyids):
+        (WebCore::sanitizeCenc):
+        (WebCore::extractKeyIDsCenc):
+        (WebCore::sanitizeWebM):
+        (WebCore::extractKeyIDsWebM):
+        (WebCore::InitDataRegistry::shared):
+        (WebCore::InitDataRegistry::InitDataRegistry):
+        (WebCore::InitDataRegistry::sanitizeInitData):
+        (WebCore::InitDataRegistry::extractKeyIDs):
+        (WebCore::InitDataRegistry::registerInitDataType):
+        * Modules/encryptedmedia/InitDataRegistry.h:
+        * Modules/encryptedmedia/MediaKeySession.cpp:
+        (WebCore::messageEventName):
+        (WebCore::MediaKeySession::MediaKeySession):
+        (WebCore::MediaKeySession::generateRequest):
+        (WebCore::MediaKeySession::enqueueMessage):
+        * Modules/encryptedmedia/MediaKeySession.h:
+        * Modules/encryptedmedia/MediaKeys.cpp:
+        (WebCore::MediaKeys::setServerCertificate):
+        * WebCore.xcodeproj/project.pbxproj:
+        * testing/MockCDMFactory.cpp:
+        (WebCore::MockCDMFactory::addKeysToSessionWithID):
+        (WebCore::MockCDMFactory::setSupportedDataTypes):
+        (WebCore::MockCDM::supportsInitDataType):
+        (WebCore::MockCDM::supportsConfiguration):
+        (WebCore::MockCDM::supportsConfigurationWithRestrictions):
+        (WebCore::MockCDM::supportsSessionTypeWithConfiguration):
+        (WebCore::MockCDM::supportsRobustness):
+        (WebCore::MockCDM::distinctiveIdentifiersRequirement):
+        (WebCore::MockCDM::persistentStateRequirement):
+        (WebCore::MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable):
+        (WebCore::MockCDM::supportsInitData):
+        (WebCore::MockCDMInstance::setServerCertificate):
+        (WebCore::MockCDMInstance::requestLicense):
+        * testing/MockCDMFactory.h:
+        (WebCore::MockCDMFactory::supportedDataTypes):
+        (WebCore::MockCDMFactory::hasSessionWithID):
+        (WebCore::MockCDMFactory::removeSessionWithID):
+        (WebCore::MockCDMFactory::setSupportedDataTypes): Deleted.
+
+2017-01-10  Jer Noble  &lt;jer.noble@apple.com&gt;
+
</ins><span class="cx">         Add support for MediaKeys.createSession().
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=166796
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaCDMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.cpp        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CDMPrivate.h&quot;
</span><span class="cx"> #include &quot;Document.h&quot;
</span><ins>+#include &quot;InitDataRegistry.h&quot;
</ins><span class="cx"> #include &quot;MediaKeysRestrictions.h&quot;
</span><span class="cx"> #include &quot;MediaPlayer.h&quot;
</span><span class="cx"> #include &quot;NotImplemented.h&quot;
</span><span class="lines">@@ -634,6 +635,21 @@
</span><span class="cx">     return m_private &amp;&amp; m_private-&gt;supportsSessions();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool CDM::supportsInitDataType(const AtomicString&amp; initDataType) const
+{
+    return m_private &amp;&amp; m_private-&gt;supportsInitDataType(initDataType);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+RefPtr&lt;SharedBuffer&gt; CDM::sanitizeInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp; initData)
+{
+    return InitDataRegistry::shared().sanitizeInitData(initDataType, initData);
+}
+
+bool CDM::supportsInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp; initData)
+{
+    return m_private &amp;&amp; m_private-&gt;supportsInitData(initDataType, initData);
+}
+
+}
+
</ins><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaCDMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDM.h (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/CDM.h        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDM.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ContextDestructionObserver.h&quot;
</span><span class="cx"> #include &quot;MediaKeySystemConfiguration.h&quot;
</span><ins>+#include &quot;SharedBuffer.h&quot;
</ins><span class="cx"> #include &lt;functional&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Ref.h&gt;
</span><span class="lines">@@ -43,6 +44,7 @@
</span><span class="cx"> class CDMPrivate;
</span><span class="cx"> class Document;
</span><span class="cx"> class ScriptExecutionContext;
</span><ins>+class SharedBuffer;
</ins><span class="cx"> 
</span><span class="cx"> struct MediaKeysRestrictions;
</span><span class="cx"> 
</span><span class="lines">@@ -73,7 +75,11 @@
</span><span class="cx">     RefPtr&lt;CDMInstance&gt; createInstance();
</span><span class="cx">     bool supportsServerCertificates() const;
</span><span class="cx">     bool supportsSessions() const;
</span><ins>+    bool supportsInitDataType(const AtomicString&amp;) const;
</ins><span class="cx"> 
</span><ins>+    RefPtr&lt;SharedBuffer&gt; sanitizeInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp;);
+    bool supportsInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     CDM(Document&amp;, const String&amp; keySystem);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaCDMInstanceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -30,13 +30,10 @@
</span><span class="cx"> #include &lt;wtf/Forward.h&gt;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> 
</span><del>-namespace JSC {
-class ArrayBuffer;
-}
-
</del><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> struct MediaKeySystemConfiguration;
</span><ins>+class SharedBuffer;
</ins><span class="cx"> 
</span><span class="cx"> class CDMInstance : public RefCounted&lt;CDMInstance&gt; {
</span><span class="cx"> public:
</span><span class="lines">@@ -50,7 +47,16 @@
</span><span class="cx">     virtual SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&amp;) = 0;
</span><span class="cx">     virtual SuccessValue setDistinctiveIdentifiersAllowed(bool) = 0;
</span><span class="cx">     virtual SuccessValue setPersistentStateAllowed(bool) = 0;
</span><del>-    virtual SuccessValue setServerCertificate(JSC::ArrayBuffer&amp;) = 0;
</del><ins>+    virtual SuccessValue setServerCertificate(Ref&lt;SharedBuffer&gt;&amp;&amp;) = 0;
+
+    enum class LicenseType {
+        Temporary,
+        Persistable,
+        UsageRecord,
+    };
+
+    using LicenseCallback = Function&lt;void(Ref&lt;SharedBuffer&gt;&amp;&amp; message, const String&amp; sessionId, bool needsIndividualization, SuccessValue succeeded)&gt;;
+    virtual void requestLicense(LicenseType, const AtomicString&amp; initDataType, Ref&lt;SharedBuffer&gt;&amp;&amp; initData, LicenseCallback) = 0;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaCDMPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/CDMPrivate.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -41,18 +41,19 @@
</span><span class="cx"> public:
</span><span class="cx">     virtual ~CDMPrivate() { }
</span><span class="cx"> 
</span><del>-    virtual bool supportsInitDataType(const String&amp;) = 0;
-    virtual bool supportsConfiguration(const MediaKeySystemConfiguration&amp;) = 0;
-    virtual bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) = 0;
-    virtual bool supportsSessionTypeWithConfiguration(MediaKeySessionType&amp;, const MediaKeySystemConfiguration&amp;) = 0;
-    virtual bool supportsRobustness(const String&amp;) = 0;
-    virtual MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) = 0;
-    virtual MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) = 0;
-    virtual bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;) = 0;
</del><ins>+    virtual bool supportsInitDataType(const AtomicString&amp;) const = 0;
+    virtual bool supportsConfiguration(const MediaKeySystemConfiguration&amp;) const = 0;
+    virtual bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const = 0;
+    virtual bool supportsSessionTypeWithConfiguration(MediaKeySessionType&amp;, const MediaKeySystemConfiguration&amp;) const = 0;
+    virtual bool supportsRobustness(const String&amp;) const = 0;
+    virtual MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const = 0;
+    virtual MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const = 0;
+    virtual bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;) const = 0;
</ins><span class="cx">     virtual RefPtr&lt;CDMInstance&gt; createInstance() = 0;
</span><span class="cx">     virtual void loadAndInitialize() = 0;
</span><span class="cx">     virtual bool supportsServerCertificates() const = 0;
</span><span class="cx">     virtual bool supportsSessions() const = 0;
</span><ins>+    virtual bool supportsInitData(const AtomicString&amp;, const SharedBuffer&amp;) const = 0;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaInitDataRegistrycpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp (0 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp                                (rev 0)
+++ trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.cpp        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -0,0 +1,165 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;InitDataRegistry.h&quot;
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include &quot;NotImplemented.h&quot;
+#include &quot;SharedBuffer.h&quot;
+#include &quot;inspector/InspectorValues.h&quot;
+#include &lt;wtf/NeverDestroyed.h&gt;
+#include &lt;wtf/text/Base64.h&gt;
+
+using namespace Inspector;
+
+namespace WebCore {
+
+static Vector&lt;Ref&lt;SharedBuffer&gt;&gt; extractKeyIDsKeyids(const SharedBuffer&amp; buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/keyids.html#format
+    String json { buffer.data(), buffer.size() };
+
+    RefPtr&lt;InspectorValue&gt; value;
+    if (!InspectorValue::parseJSON(json, value))
+        return { };
+
+    RefPtr&lt;InspectorObject&gt; object;
+    if (!value-&gt;asObject(object))
+        return { };
+
+    RefPtr&lt;InspectorArray&gt; kidsArray;
+    if (!object-&gt;getArray(&quot;kids&quot;, kidsArray))
+        return { };
+
+    Vector&lt;Ref&lt;SharedBuffer&gt;&gt; keyIDs;
+    for (auto&amp; value : *kidsArray) {
+        String keyID;
+        if (!value-&gt;asString(keyID))
+            continue;
+
+        Vector&lt;char&gt; keyIDData;
+        if (!WTF::base64Decode(keyID, { keyIDData }))
+            continue;
+
+        Ref&lt;SharedBuffer&gt; keyIDBuffer = SharedBuffer::adoptVector(keyIDData);
+        keyIDs.append(WTFMove(keyIDBuffer));
+    }
+
+    return keyIDs;
+}
+
+static RefPtr&lt;SharedBuffer&gt; sanitizeKeyids(const SharedBuffer&amp; buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/keyids.html#format
+    Vector&lt;Ref&lt;SharedBuffer&gt;&gt; keyIDBuffer = extractKeyIDsKeyids(buffer);
+    if (keyIDBuffer.isEmpty())
+        return nullptr;
+
+    auto object = InspectorObject::create();
+    auto kidsArray = InspectorArray::create();
+    for (auto&amp; buffer : keyIDBuffer)
+        kidsArray-&gt;pushString(base64Encode(buffer-&gt;data(), buffer-&gt;size()));
+    object-&gt;setArray(&quot;kids&quot;, WTFMove(kidsArray));
+
+    CString jsonData = object-&gt;toJSONString().utf8();
+    return SharedBuffer::create(jsonData.data(), jsonData.length());
+}
+
+static RefPtr&lt;SharedBuffer&gt; sanitizeCenc(const SharedBuffer&amp; buffer)
+{
+    // 4. Common SystemID and PSSH Box Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
+    notImplemented();
+    return buffer.copy();
+}
+
+static Vector&lt;Ref&lt;SharedBuffer&gt;&gt; extractKeyIDsCenc(const SharedBuffer&amp;)
+{
+    // 4. Common SystemID and PSSH Box Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/cenc.html#common-system
+    notImplemented();
+    return { };
+}
+
+static RefPtr&lt;SharedBuffer&gt; sanitizeWebM(const SharedBuffer&amp; buffer)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/webm.html#format
+    notImplemented();
+    return buffer.copy();
+}
+
+static Vector&lt;Ref&lt;SharedBuffer&gt;&gt; extractKeyIDsWebM(const SharedBuffer&amp;)
+{
+    // 1. Format
+    // https://w3c.github.io/encrypted-media/format-registry/initdata/webm.html#format
+    notImplemented();
+    return { };
+}
+
+InitDataRegistry&amp; InitDataRegistry::shared()
+{
+    static NeverDestroyed&lt;InitDataRegistry&gt; registry;
+    return registry.get();
+}
+
+InitDataRegistry::InitDataRegistry()
+{
+    registerInitDataType(&quot;keyids&quot;, { &amp;sanitizeKeyids, &amp;extractKeyIDsKeyids });
+    registerInitDataType(&quot;cenc&quot;, { &amp;sanitizeCenc, &amp;extractKeyIDsCenc });
+    registerInitDataType(&quot;webm&quot;, { &amp;sanitizeWebM, &amp;extractKeyIDsWebM });
+}
+
+InitDataRegistry::~InitDataRegistry() = default;
+
+RefPtr&lt;SharedBuffer&gt; InitDataRegistry::sanitizeInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp; buffer)
+{
+    auto iter = m_types.find(initDataType);
+    if (iter == m_types.end() || !iter-&gt;value.sanitizeInitData)
+        return nullptr;
+    return iter-&gt;value.sanitizeInitData(buffer);
+}
+
+Vector&lt;Ref&lt;SharedBuffer&gt;&gt; InitDataRegistry::extractKeyIDs(const AtomicString&amp; initDataType, const SharedBuffer&amp; buffer)
+{
+    auto iter = m_types.find(initDataType);
+    if (iter == m_types.end() || !iter-&gt;value.sanitizeInitData)
+        return { };
+    return iter-&gt;value.extractKeyIDs(buffer);
+}
+
+void InitDataRegistry::registerInitDataType(const AtomicString&amp; initDataType, InitDataTypeCallbacks&amp;&amp; callbacks)
+{
+    ASSERT(!m_types.contains(initDataType));
+    m_types.set(initDataType, WTFMove(callbacks));
+}
+
+}
+
+#endif // ENABLE(ENCRYPTED_MEDIA)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaInitDataRegistryhfromrev210554trunkSourceWebCoreModulesencryptedmediaCDMInstanceh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h (from rev 210554, trunk/Source/WebCore/Modules/encryptedmedia/CDMInstance.h) (0 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h                                (rev 0)
+++ trunk/Source/WebCore/Modules/encryptedmedia/InitDataRegistry.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include &lt;wtf/Function.h&gt;
+#include &lt;wtf/HashMap.h&gt;
+#include &lt;wtf/Ref.h&gt;
+#include &lt;wtf/RefPtr.h&gt;
+#include &lt;wtf/Vector.h&gt;
+#include &lt;wtf/text/AtomicString.h&gt;
+#include &lt;wtf/text/AtomicStringHash.h&gt;
+
+namespace WebCore {
+
+class SharedBuffer;
+
+class InitDataRegistry {
+public:
+    WEBCORE_EXPORT static InitDataRegistry&amp; shared();
+    friend class NeverDestroyed&lt;InitDataRegistry&gt;;
+
+    RefPtr&lt;SharedBuffer&gt; sanitizeInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp;);
+    WEBCORE_EXPORT Vector&lt;Ref&lt;SharedBuffer&gt;&gt; extractKeyIDs(const AtomicString&amp; initDataType, const SharedBuffer&amp;);
+
+    struct InitDataTypeCallbacks {
+        using SanitizeInitDataCallback = Function&lt;RefPtr&lt;SharedBuffer&gt;(const SharedBuffer&amp;)&gt;;
+        using ExtractKeyIDsCallback = Function&lt;Vector&lt;Ref&lt;SharedBuffer&gt;&gt;(const SharedBuffer&amp;)&gt;;
+
+        SanitizeInitDataCallback sanitizeInitData;
+        ExtractKeyIDsCallback extractKeyIDs;
+    };
+    void registerInitDataType(const AtomicString&amp; initDataType, InitDataTypeCallbacks&amp;&amp;);
+
+private:
+    InitDataRegistry();
+    ~InitDataRegistry();
+
+    HashMap&lt;AtomicString, InitDataTypeCallbacks&gt; m_types;
+};
+
+}
+
+#endif // ENABLE(ENCRYPTED_MEDIA)
</ins></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaMediaKeySessioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -33,11 +33,21 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CDM.h&quot;
</span><span class="cx"> #include &quot;CDMInstance.h&quot;
</span><ins>+#include &quot;MediaKeyMessageEvent.h&quot;
+#include &quot;MediaKeyMessageType.h&quot;
</ins><span class="cx"> #include &quot;MediaKeyStatusMap.h&quot;
</span><span class="cx"> #include &quot;NotImplemented.h&quot;
</span><ins>+#include &quot;SharedBuffer.h&quot;
+#include &lt;wtf/NeverDestroyed.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><ins>+static AtomicString&amp; messageEventName()
+{
+    NeverDestroyed&lt;AtomicString&gt; message { &quot;message&quot; };
+    return message.get();
+}
+
</ins><span class="cx"> Ref&lt;MediaKeySession&gt; MediaKeySession::create(ScriptExecutionContext&amp; context, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref&lt;CDM&gt;&amp;&amp; implementation, Ref&lt;CDMInstance&gt;&amp;&amp; instance)
</span><span class="cx"> {
</span><span class="cx">     auto session = adoptRef(*new MediaKeySession(context, sessionType, useDistinctiveIdentifier, WTFMove(implementation), WTFMove(instance)));
</span><span class="lines">@@ -53,6 +63,8 @@
</span><span class="cx">     , m_sessionType(sessionType)
</span><span class="cx">     , m_implementation(WTFMove(implementation))
</span><span class="cx">     , m_instance(WTFMove(instance))
</span><ins>+    , m_eventQueue(*this)
+    , m_weakPtrFactory(this)
</ins><span class="cx"> {
</span><span class="cx">     // https://w3c.github.io/encrypted-media/#dom-mediakeys-setservercertificate
</span><span class="cx">     // W3C Editor's Draft 09 November 2016
</span><span class="lines">@@ -94,9 +106,143 @@
</span><span class="cx">     return m_keyStatuses.copyRef();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaKeySession::generateRequest(const String&amp;, const BufferSource&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;)
</del><ins>+void MediaKeySession::generateRequest(const AtomicString&amp; initDataType, const BufferSource&amp; initData, Ref&lt;DeferredPromise&gt;&amp;&amp; promise)
</ins><span class="cx"> {
</span><del>-    notImplemented();
</del><ins>+    // https://w3c.github.io/encrypted-media/#dom-mediakeysession-generaterequest
+    // W3C Editor's Draft 09 November 2016
+
+    // When this method is invoked, the user agent must run the following steps:
+    // 1. If this object is closed, return a promise rejected with an InvalidStateError.
+    // 2. If this object's uninitialized value is false, return a promise rejected with an InvalidStateError.
+    if (m_closed || !m_uninitialized) {
+        promise-&gt;reject(INVALID_STATE_ERR);
+        return;
+    }
+
+    // 3. Let this object's uninitialized value be false.
+    m_uninitialized = false;
+
+    // 4. If initDataType is the empty string, return a promise rejected with a newly created TypeError.
+    // 5. If initData is an empty array, return a promise rejected with a newly created TypeError.
+    if (initDataType.isEmpty() || !initData.length()) {
+        promise-&gt;reject(TypeError);
+        return;
+    }
+
+    // 6. If the Key System implementation represented by this object's cdm implementation value does not support
+    //    initDataType as an Initialization Data Type, return a promise rejected with a NotSupportedError. String
+    //    comparison is case-sensitive.
+    if (!m_implementation-&gt;supportsInitDataType(initDataType)) {
+        promise-&gt;reject(NOT_SUPPORTED_ERR);
+        return;
+    }
+
+    // 7. Let init data be a copy of the contents of the initData parameter.
+    // 8. Let session type be this object's session type.
+    // 9. Let promise be a new promise.
+    // 10. Run the following steps in parallel:
+    m_taskQueue.enqueueTask([this, initData = SharedBuffer::create(initData.data(), initData.length()), initDataType, promise = WTFMove(promise)] () mutable {
+        // 10.1. If the init data is not valid for initDataType, reject promise with a newly created TypeError.
+        // 10.2. Let sanitized init data be a validated and sanitized version of init data.
+        RefPtr&lt;SharedBuffer&gt; sanitizedInitData = m_implementation-&gt;sanitizeInitData(initDataType, initData);
+
+        // 10.3. If the preceding step failed, reject promise with a newly created TypeError.
+        if (!sanitizedInitData) {
+            promise-&gt;reject(TypeError);
+            return;
+        }
+
+        // 10.4. If sanitized init data is empty, reject promise with a NotSupportedError.
+        if (sanitizedInitData-&gt;isEmpty()) {
+            promise-&gt;reject(NOT_SUPPORTED_ERR);
+            return;
+        }
+
+        // 10.5. Let session id be the empty string.
+        // 10.6. Let message be null.
+        // 10.7. Let message type be null.
+        // 10.8. Let cdm be the CDM instance represented by this object's cdm instance value.
+        // 10.9. Use the cdm to execute the following steps:
+        // 10.9.1. If the sanitized init data is not supported by the cdm, reject promise with a NotSupportedError.
+        if (!m_implementation-&gt;supportsInitData(initDataType, *sanitizedInitData)) {
+            promise-&gt;reject(NOT_SUPPORTED_ERR);
+            return;
+        }
+
+        // 10.9.2 Follow the steps for the value of session type from the following list:
+        CDMInstance::LicenseType requestedLicenseType;
+        switch (m_sessionType) {
+        case MediaKeySessionType::Temporary:
+            // ↳ &quot;temporary&quot;
+            // Let requested license type be a temporary non-persistable license.
+            requestedLicenseType = CDMInstance::LicenseType::Temporary;
+            break;
+        case MediaKeySessionType::PersistentLicense:
+            // ↳ &quot;persistent-license&quot;
+            // Let requested license type be a persistable license.
+            requestedLicenseType = CDMInstance::LicenseType::Persistable;
+            break;
+        case MediaKeySessionType::PersistentUsageRecord:
+            // ↳ &quot;persistent-usage-record&quot;
+            // 1. Initialize this object's record of key usage as follows.
+            //    Set the list of key IDs known to the session to an empty list.
+            m_recordOfKeyUsage.clear();
+
+            //    Set the first decrypt time to null.
+            m_firstDecryptTime = 0;
+
+            //    Set the latest decrypt time to null.
+            m_latestDecryptTime = 0;
+
+            // 2. Let requested license type be a non-persistable license that will
+            //    persist a record of key usage.
+            requestedLicenseType = CDMInstance::LicenseType::UsageRecord;
+            break;
+        }
+
+        m_instance-&gt;requestLicense(requestedLicenseType, initDataType, WTFMove(initData), [this, weakThis = m_weakPtrFactory.createWeakPtr(), promise = WTFMove(promise)] (Ref&lt;SharedBuffer&gt;&amp;&amp; message, const String&amp; sessionId, bool needsIndividualization, CDMInstance::SuccessValue succeeded) mutable {
+            if (!weakThis)
+                return;
+
+            // 10.9.3. Let session id be a unique Session ID string.
+
+            MediaKeyMessageType messageType;
+            if (!needsIndividualization) {
+                // 10.9.4. If a license request for the requested license type can be generated based on the sanitized init data:
+                // 10.9.4.1. Let message be a license request for the requested license type generated based on the sanitized init data interpreted per initDataType.
+                // 10.9.4.2. Let message type be &quot;license-request&quot;.
+                messageType = MediaKeyMessageType::LicenseRequest;
+            } else {
+                // 10.9.5. Otherwise:
+                // 10.9.5.1. Let message be the request that needs to be processed before a license request request for the requested license
+                //           type can be generated based on the sanitized init data.
+                // 10.9.5.2. Let message type reflect the type of message, either &quot;license-request&quot; or &quot;individualization-request&quot;.
+                messageType = MediaKeyMessageType::IndividualizationRequest;
+            }
+
+            // 10.10. Queue a task to run the following steps:
+            m_taskQueue.enqueueTask([this, promise = WTFMove(promise), message = WTFMove(message), messageType, sessionId, succeeded] () mutable {
+                // 10.10.1. If any of the preceding steps failed, reject promise with a new DOMException whose name is the appropriate error name.
+                if (succeeded == CDMInstance::SuccessValue::Failed) {
+                    promise-&gt;reject(NOT_SUPPORTED_ERR);
+                    return;
+                }
+                // 10.10.2. Set the sessionId attribute to session id.
+                m_sessionId = sessionId;
+
+                // 10.9.3. Let this object's callable value be true.
+                m_callable = true;
+
+                // 10.9.3. Run the Queue a &quot;message&quot; Event algorithm on the session, providing message type and message.
+                enqueueMessage(messageType, message);
+
+                // 10.9.3. Resolve promise.
+                promise-&gt;resolve();
+            });
+        });
+    });
+
+    // 11. Return promise.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MediaKeySession::load(const String&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;)
</span><span class="lines">@@ -119,6 +265,21 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MediaKeySession::enqueueMessage(MediaKeyMessageType messageType, const SharedBuffer&amp; message)
+{
+    // 6.4.1 Queue a &quot;message&quot; Event
+    // https://w3c.github.io/encrypted-media/#queue-message
+    // W3C Editor's Draft 09 November 2016
+
+    // The following steps are run:
+    // 1. Let the session be the specified MediaKeySession object.
+    // 2. Queue a task to create an event named message that does not bubble and is not cancellable using the MediaKeyMessageEvent
+    //    interface with its type attribute set to message and its isTrusted attribute initialized to true, and dispatch it at the
+    //    session.
+    auto messageEvent = MediaKeyMessageEvent::create(messageEventName(), {messageType, message.createArrayBuffer()}, Event::IsTrusted::Yes);
+    m_eventQueue.enqueueEvent(WTFMove(messageEvent));
+}
+
</ins><span class="cx"> bool MediaKeySession::hasPendingActivity() const
</span><span class="cx"> {
</span><span class="cx">     notImplemented();
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaMediaKeySessionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -33,9 +33,13 @@
</span><span class="cx"> #include &quot;ActiveDOMObject.h&quot;
</span><span class="cx"> #include &quot;EventTarget.h&quot;
</span><span class="cx"> #include &quot;GenericEventQueue.h&quot;
</span><ins>+#include &quot;GenericTaskQueue.h&quot;
</ins><span class="cx"> #include &quot;JSDOMPromise.h&quot;
</span><ins>+#include &quot;MediaKeyMessageType.h&quot;
</ins><span class="cx"> #include &quot;MediaKeySessionType.h&quot;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><ins>+#include &lt;wtf/Vector.h&gt;
+#include &lt;wtf/WeakPtr.h&gt;
</ins><span class="cx"> #include &lt;wtf/text/WTFString.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -45,6 +49,7 @@
</span><span class="cx"> class CDMInstance;
</span><span class="cx"> class MediaKeyStatusMap;
</span><span class="cx"> class MediaKeys;
</span><ins>+class SharedBuffer;
</ins><span class="cx"> 
</span><span class="cx"> class MediaKeySession final : public RefCounted&lt;MediaKeySession&gt;, public EventTargetWithInlineData, public ActiveDOMObject {
</span><span class="cx"> public:
</span><span class="lines">@@ -58,7 +63,7 @@
</span><span class="cx">     double expiration() const;
</span><span class="cx">     Ref&lt;MediaKeyStatusMap&gt; keyStatuses() const;
</span><span class="cx"> 
</span><del>-    void generateRequest(const String&amp;, const BufferSource&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;);
</del><ins>+    void generateRequest(const AtomicString&amp;, const BufferSource&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;);
</ins><span class="cx">     void load(const String&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;);
</span><span class="cx">     void update(const BufferSource&amp;, Ref&lt;DeferredPromise&gt;&amp;&amp;);
</span><span class="cx">     void close(Ref&lt;DeferredPromise&gt;&amp;&amp;);
</span><span class="lines">@@ -66,6 +71,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     MediaKeySession(ScriptExecutionContext&amp;, MediaKeySessionType, bool useDistinctiveIdentifier, Ref&lt;CDM&gt;&amp;&amp;, Ref&lt;CDMInstance&gt;&amp;&amp;);
</span><ins>+    void enqueueMessage(MediaKeyMessageType, const SharedBuffer&amp;);
</ins><span class="cx"> 
</span><span class="cx">     // EventTarget
</span><span class="cx">     EventTargetInterface eventTargetInterface() const override { return MediaKeySessionEventTargetInterfaceType; }
</span><span class="lines">@@ -89,6 +95,12 @@
</span><span class="cx">     MediaKeySessionType m_sessionType;
</span><span class="cx">     Ref&lt;CDM&gt; m_implementation;
</span><span class="cx">     Ref&lt;CDMInstance&gt; m_instance;
</span><ins>+    GenericEventQueue m_eventQueue;
+    GenericTaskQueue&lt;Timer&gt; m_taskQueue;
+    Vector&lt;Ref&lt;SharedBuffer&gt;&gt; m_recordOfKeyUsage;
+    double m_firstDecryptTime { 0 };
+    double m_latestDecryptTime { 0 };
+    WeakPtrFactory&lt;MediaKeySession&gt; m_weakPtrFactory;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesencryptedmediaMediaKeyscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> #include &quot;CDMInstance.h&quot;
</span><span class="cx"> #include &quot;MediaKeySession.h&quot;
</span><span class="cx"> #include &quot;NotImplemented.h&quot;
</span><del>-#include &lt;runtime/ArrayBuffer.h&gt;
</del><ins>+#include &quot;SharedBuffer.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="lines">@@ -90,7 +90,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // 3. Let certificate be a copy of the contents of the serverCertificate parameter.
</span><del>-    auto certificate = ArrayBuffer::create(serverCertificate.data(), serverCertificate.length());
</del><ins>+    auto certificate = SharedBuffer::create(serverCertificate.data(), serverCertificate.length());
</ins><span class="cx"> 
</span><span class="cx">     // 4. Let promise be a new promise.
</span><span class="cx">     // 5. Run the following steps in parallel:
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx"> 
</span><span class="cx">     m_taskQueue.enqueueTask([this, certificate = WTFMove(certificate), promise = WTFMove(promise)] () mutable {
</span><span class="cx">         // 5.1. Use this object's cdm instance to process certificate.
</span><del>-        if (m_instance-&gt;setServerCertificate(certificate) == CDMInstance::Failed) {
</del><ins>+        if (m_instance-&gt;setServerCertificate(WTFMove(certificate)) == CDMInstance::Failed) {
</ins><span class="cx">             // 5.2. If the preceding step failed, resolve promise with a new DOMException whose name is the appropriate error name.
</span><span class="cx">             promise-&gt;reject(INVALID_STATE_ERR);
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -5717,6 +5717,8 @@
</span><span class="cx">                 CCC2B51415F613060048CDD6 /* DeviceClient.h in Headers */ = {isa = PBXBuildFile; fileRef = CCC2B51015F613060048CDD6 /* DeviceClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 CCC2B51515F613060048CDD6 /* DeviceController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CCC2B51115F613060048CDD6 /* DeviceController.cpp */; };
</span><span class="cx">                 CCC2B51615F613060048CDD6 /* DeviceController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCC2B51215F613060048CDD6 /* DeviceController.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                CD063F821E23FA8900812BE3 /* InitDataRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */; };
+                CD063F831E23FA8900812BE3 /* InitDataRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = CD063F811E23FA8900812BE3 /* InitDataRegistry.h */; };
</ins><span class="cx">                 CD0EEE0E14743F39003EAFA2 /* AudioDestinationIOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CD0EEE0B14743E35003EAFA2 /* AudioDestinationIOS.cpp */; };
</span><span class="cx">                 CD127DED14F3097D00E84779 /* WebCoreFullScreenWindow.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD127DEB14F3097900E84779 /* WebCoreFullScreenWindow.mm */; };
</span><span class="cx">                 CD127DEE14F3098400E84779 /* WebCoreFullScreenWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = CD127DEA14F3097900E84779 /* WebCoreFullScreenWindow.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -13643,6 +13645,8 @@
</span><span class="cx">                 CCC2B51015F613060048CDD6 /* DeviceClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceClient.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CCC2B51115F613060048CDD6 /* DeviceController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeviceController.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CCC2B51215F613060048CDD6 /* DeviceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceController.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitDataRegistry.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                CD063F811E23FA8900812BE3 /* InitDataRegistry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitDataRegistry.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 CD0EEE0A14743E34003EAFA2 /* AudioDestinationIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioDestinationIOS.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CD0EEE0B14743E35003EAFA2 /* AudioDestinationIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDestinationIOS.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 CD127DEA14F3097900E84779 /* WebCoreFullScreenWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreFullScreenWindow.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -22773,6 +22777,8 @@
</span><span class="cx">                                 CDF4B7141E00B7E500E235A2 /* CDM.h */,
</span><span class="cx">                                 CD9D05421E1EFA12003B4C4F /* CDMInstance.h */,
</span><span class="cx">                                 CDF4B7251E03C15B00E235A2 /* CDMPrivate.h */,
</span><ins>+                                CD063F801E23FA8900812BE3 /* InitDataRegistry.cpp */,
+                                CD063F811E23FA8900812BE3 /* InitDataRegistry.h */,
</ins><span class="cx">                                 2D9BF72F1DBFDC0F007A7D99 /* MediaKeyMessageEvent.cpp */,
</span><span class="cx">                                 2D9BF7301DBFDC0F007A7D99 /* MediaKeyMessageEvent.h */,
</span><span class="cx">                                 2D9BF6F51DBFB71F007A7D99 /* MediaKeyMessageEvent.idl */,
</span><span class="lines">@@ -27867,6 +27873,7 @@
</span><span class="cx">                                 7CE58D501DD69A1E00128552 /* SVGNumber.h in Headers */,
</span><span class="cx">                                 B2227A510D00BF220071B782 /* SVGNumberList.h in Headers */,
</span><span class="cx">                                 B2227A570D00BF220071B782 /* SVGParserUtilities.h in Headers */,
</span><ins>+                                CD063F831E23FA8900812BE3 /* InitDataRegistry.h in Headers */,
</ins><span class="cx">                                 2D3A0E3613A7D76100E85AF0 /* SVGParsingError.h in Headers */,
</span><span class="cx">                                 84C6784D1214814700A92902 /* SVGPathBlender.h in Headers */,
</span><span class="cx">                                 8476C9EB11DF6A2900555B02 /* SVGPathBuilder.h in Headers */,
</span><span class="lines">@@ -30820,6 +30827,7 @@
</span><span class="cx">                                 B27535630B053814002CE64F /* PathCG.cpp in Sources */,
</span><span class="cx">                                 A88DD4890B4629B000C02990 /* PathTraversalState.cpp in Sources */,
</span><span class="cx">                                 2D5002FB1B56D7990020AAF7 /* PathUtilities.cpp in Sources */,
</span><ins>+                                CD063F821E23FA8900812BE3 /* InitDataRegistry.cpp in Sources */,
</ins><span class="cx">                                 A8FA6E5E0E4CFDED00D5CF49 /* Pattern.cpp in Sources */,
</span><span class="cx">                                 A80A38FE0E50CC8200A25EBC /* PatternCG.cpp in Sources */,
</span><span class="cx">                                 1A8A646C1D19FF8700D0E00F /* PaymentCocoa.mm in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockCDMFactorycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockCDMFactory.cpp (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockCDMFactory.cpp        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/testing/MockCDMFactory.cpp        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -28,7 +28,10 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ENCRYPTED_MEDIA)
</span><span class="cx"> 
</span><ins>+#include &quot;InitDataRegistry.h&quot;
+#include &quot;UUID.h&quot;
</ins><span class="cx"> #include &lt;runtime/ArrayBuffer.h&gt;
</span><ins>+#include &lt;wtf/text/StringHash.h&gt;
</ins><span class="cx"> #include &lt;wtf/text/StringView.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -58,6 +61,24 @@
</span><span class="cx">     return equalIgnoringASCIICase(keySystem, &quot;org.webkit.mock&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MockCDMFactory::addKeysToSessionWithID(const String&amp; id, Vector&lt;Ref&lt;SharedBuffer&gt;&gt;&amp;&amp; keys)
+{
+    auto addResult = m_sessions.add(id, WTFMove(keys));
+    if (addResult.isNewEntry)
+        return;
+
+    auto&amp; value = addResult.iterator-&gt;value;
+    for (auto&amp; key : keys)
+        value.append(WTFMove(key));
+}
+
+void MockCDMFactory::setSupportedDataTypes(Vector&lt;String&gt;&amp;&amp; types)
+{
+    m_supportedDataTypes.clear();
+    for (auto&amp; type : types)
+        m_supportedDataTypes.append(type);
+}
+
</ins><span class="cx"> std::unique_ptr&lt;CDMPrivate&gt; MockCDMFactory::createCDM(CDM&amp;)
</span><span class="cx"> {
</span><span class="cx">     return std::make_unique&lt;MockCDM&gt;(m_weakPtrFactory.createWeakPtr());
</span><span class="lines">@@ -69,7 +90,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::supportsInitDataType(const String&amp; initDataType)
</del><ins>+bool MockCDM::supportsInitDataType(const AtomicString&amp; initDataType) const
</ins><span class="cx"> {
</span><span class="cx">     if (m_factory)
</span><span class="cx">         return m_factory-&gt;supportedDataTypes().contains(initDataType);
</span><span class="lines">@@ -76,7 +97,7 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&amp;)
</del><ins>+bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     // NOTE: Implement;
</span><span class="cx">     return true;
</span><span class="lines">@@ -83,13 +104,13 @@
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;)
</del><ins>+bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     // NOTE: Implement;
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType&amp; sessionType, const MediaKeySystemConfiguration&amp;)
</del><ins>+bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType&amp; sessionType, const MediaKeySystemConfiguration&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     if (!m_factory || !m_factory-&gt;supportedSessionTypes().contains(sessionType))
</span><span class="cx">         return false;
</span><span class="lines">@@ -98,7 +119,7 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::supportsRobustness(const String&amp; robustness)
</del><ins>+bool MockCDM::supportsRobustness(const String&amp; robustness) const
</ins><span class="cx"> {
</span><span class="cx">     if (m_factory)
</span><span class="cx">         return m_factory-&gt;supportedRobustness().contains(robustness);
</span><span class="lines">@@ -105,7 +126,7 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;)
</del><ins>+MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     if (m_factory)
</span><span class="cx">         return m_factory-&gt;distinctiveIdentifiersRequirement();
</span><span class="lines">@@ -112,7 +133,7 @@
</span><span class="cx">     return MediaKeysRequirement::Optional;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;)
</del><ins>+MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     if (m_factory)
</span><span class="cx">         return m_factory-&gt;persistentStateRequirement();
</span><span class="lines">@@ -119,7 +140,7 @@
</span><span class="cx">     return MediaKeysRequirement::Optional;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;)
</del><ins>+bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;) const
</ins><span class="cx"> {
</span><span class="cx">     // NOTE: Implement;
</span><span class="cx">     return true;
</span><span class="lines">@@ -147,6 +168,15 @@
</span><span class="cx">     return m_factory &amp;&amp; m_factory-&gt;supportsSessions();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool MockCDM::supportsInitData(const AtomicString&amp; initDataType, const SharedBuffer&amp; initData) const
+{
+    if (!supportsInitDataType(initDataType))
+        return false;
+
+    UNUSED_PARAM(initData);
+    return true;
+}
+
</ins><span class="cx"> MockCDMInstance::MockCDMInstance(WeakPtr&lt;MockCDM&gt; cdm)
</span><span class="cx">     : m_cdm(cdm)
</span><span class="cx"> {
</span><span class="lines">@@ -188,9 +218,9 @@
</span><span class="cx">     return Succeeded;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(ArrayBuffer&amp; certificate)
</del><ins>+CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(Ref&lt;SharedBuffer&gt;&amp;&amp; certificate)
</ins><span class="cx"> {
</span><del>-    StringView certificateStringView(static_cast&lt;const LChar*&gt;(certificate.data()), certificate.byteLength());
</del><ins>+    StringView certificateStringView(reinterpret_cast&lt;const LChar*&gt;(certificate-&gt;data()), certificate-&gt;size());
</ins><span class="cx"> 
</span><span class="cx">     if (equalIgnoringASCIICase(certificateStringView, &quot;valid&quot;))
</span><span class="cx">         return Succeeded;
</span><span class="lines">@@ -197,6 +227,35 @@
</span><span class="cx">     return Failed;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString&amp; initDataType, Ref&lt;SharedBuffer&gt;&amp;&amp; initData, LicenseCallback callback)
+{
+    MockCDMFactory* factory = m_cdm ? m_cdm-&gt;factory() : nullptr;
+    if (!factory) {
+        callback(SharedBuffer::create(), emptyAtom, false, SuccessValue::Failed);
+        return;
+    }
+
+    if ((licenseType == LicenseType::Temporary &amp;&amp; !factory-&gt;supportedSessionTypes().contains(MediaKeySessionType::Temporary))
+        || (licenseType == LicenseType::Persistable &amp;&amp; !factory-&gt;supportedSessionTypes().contains(MediaKeySessionType::PersistentLicense))
+        || (licenseType == LicenseType::UsageRecord &amp;&amp; !factory-&gt;supportedSessionTypes().contains(MediaKeySessionType::PersistentUsageRecord))
+        || !factory-&gt;supportedDataTypes().contains(initDataType)) {
+        callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+        return;
+    }
+
+    auto keyIDs = InitDataRegistry::shared().extractKeyIDs(initDataType, initData);
+    if (keyIDs.isEmpty()) {
+        callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed);
+        return;
+    }
+
+    String sessionID = createCanonicalUUIDString();
+    factory-&gt;addKeysToSessionWithID(sessionID, WTFMove(keyIDs));
+
+    CString license { &quot;license&quot; };
+    callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+}
+
</ins><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebCoretestingMockCDMFactoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/MockCDMFactory.h (210554 => 210555)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/MockCDMFactory.h        2017-01-10 19:13:06 UTC (rev 210554)
+++ trunk/Source/WebCore/testing/MockCDMFactory.h        2017-01-10 20:09:21 UTC (rev 210555)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;CDMInstance.h&quot;
</span><span class="cx"> #include &quot;CDMPrivate.h&quot;
</span><span class="cx"> #include &quot;MediaKeysRequirement.h&quot;
</span><ins>+#include &lt;wtf/HashMap.h&gt;
</ins><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> #include &lt;wtf/WeakPtr.h&gt;
</span><span class="lines">@@ -42,8 +43,8 @@
</span><span class="cx">     static Ref&lt;MockCDMFactory&gt; create() { return adoptRef(*new MockCDMFactory); }
</span><span class="cx">     ~MockCDMFactory();
</span><span class="cx"> 
</span><del>-    const Vector&lt;String&gt;&amp; supportedDataTypes() const { return m_supportedDataTypes; }
-    void setSupportedDataTypes(Vector&lt;String&gt;&amp;&amp; types) { m_supportedDataTypes = WTFMove(types); }
</del><ins>+    const Vector&lt;AtomicString&gt;&amp; supportedDataTypes() const { return m_supportedDataTypes; }
+    void setSupportedDataTypes(Vector&lt;String&gt;&amp;&amp;);
</ins><span class="cx"> 
</span><span class="cx">     const Vector&lt;MediaKeySessionType&gt;&amp; supportedSessionTypes() const { return m_supportedSessionTypes; }
</span><span class="cx">     void setSupportedSessionTypes(Vector&lt;MediaKeySessionType&gt;&amp;&amp; types) { m_supportedSessionTypes = WTFMove(types); }
</span><span class="lines">@@ -68,6 +69,10 @@
</span><span class="cx"> 
</span><span class="cx">     void unregister();
</span><span class="cx"> 
</span><ins>+    bool hasSessionWithID(const String&amp; id) { return m_sessions.contains(id); }
+    void removeSessionWithID(const String&amp; id) { m_sessions.remove(id); }
+    void addKeysToSessionWithID(const String&amp; id, Vector&lt;Ref&lt;SharedBuffer&gt;&gt;&amp;&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     MockCDMFactory();
</span><span class="cx">     std::unique_ptr&lt;CDMPrivate&gt; createCDM(CDM&amp;) final;
</span><span class="lines">@@ -75,7 +80,7 @@
</span><span class="cx"> 
</span><span class="cx">     MediaKeysRequirement m_distinctiveIdentifiersRequirement { MediaKeysRequirement::Optional };
</span><span class="cx">     MediaKeysRequirement m_persistentStateRequirement { MediaKeysRequirement::Optional };
</span><del>-    Vector&lt;String&gt; m_supportedDataTypes;
</del><ins>+    Vector&lt;AtomicString&gt; m_supportedDataTypes;
</ins><span class="cx">     Vector&lt;MediaKeySessionType&gt; m_supportedSessionTypes;
</span><span class="cx">     Vector&lt;String&gt; m_supportedRobustness;
</span><span class="cx">     bool m_registered { true };
</span><span class="lines">@@ -83,6 +88,7 @@
</span><span class="cx">     bool m_supportsServerCertificates { true };
</span><span class="cx">     bool m_supportsSessions { true };
</span><span class="cx">     WeakPtrFactory&lt;MockCDMFactory&gt; m_weakPtrFactory;
</span><ins>+    HashMap&lt;String, Vector&lt;Ref&lt;SharedBuffer&gt;&gt;&gt; m_sessions;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class MockCDM : public CDMPrivate {
</span><span class="lines">@@ -94,18 +100,19 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class MockCDMInstance;
</span><span class="cx"> 
</span><del>-    bool supportsInitDataType(const String&amp;) final;
-    bool supportsConfiguration(const MediaKeySystemConfiguration&amp;) final;
-    bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) final;
-    bool supportsSessionTypeWithConfiguration(MediaKeySessionType&amp;, const MediaKeySystemConfiguration&amp;) final;
-    bool supportsRobustness(const String&amp;) final;
-    MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) final;
-    MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) final;
-    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;) final;
</del><ins>+    bool supportsInitDataType(const AtomicString&amp;) const final;
+    bool supportsConfiguration(const MediaKeySystemConfiguration&amp;) const final;
+    bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const final;
+    bool supportsSessionTypeWithConfiguration(MediaKeySessionType&amp;, const MediaKeySystemConfiguration&amp;) const final;
+    bool supportsRobustness(const String&amp;) const final;
+    MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const final;
+    MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&amp;, const MediaKeysRestrictions&amp;) const final;
+    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&amp;) const final;
</ins><span class="cx">     RefPtr&lt;CDMInstance&gt; createInstance() final;
</span><span class="cx">     void loadAndInitialize() final;
</span><span class="cx">     bool supportsServerCertificates() const final;
</span><span class="cx">     bool supportsSessions() const final;
</span><ins>+    bool supportsInitData(const AtomicString&amp;, const SharedBuffer&amp;) const final;
</ins><span class="cx"> 
</span><span class="cx">     WeakPtr&lt;MockCDMFactory&gt; m_factory;
</span><span class="cx">     WeakPtrFactory&lt;MockCDM&gt; m_weakPtrFactory;
</span><span class="lines">@@ -119,7 +126,8 @@
</span><span class="cx">     SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&amp;) final;
</span><span class="cx">     SuccessValue setDistinctiveIdentifiersAllowed(bool) final;
</span><span class="cx">     SuccessValue setPersistentStateAllowed(bool) final;
</span><del>-    SuccessValue setServerCertificate(JSC::ArrayBuffer&amp;) final;
</del><ins>+    SuccessValue setServerCertificate(Ref&lt;SharedBuffer&gt;&amp;&amp;) final;
+    void requestLicense(LicenseType, const AtomicString&amp; initDataType, Ref&lt;SharedBuffer&gt;&amp;&amp; initData, LicenseCallback) final;
</ins><span class="cx"> 
</span><span class="cx">     WeakPtr&lt;MockCDM&gt; m_cdm;
</span><span class="cx">     bool m_distinctiveIdentifiersAllowed { true };
</span></span></pre>
</div>
</div>

</body>
</html>