<!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>[269810] 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/269810">269810</a></dd>
<dt>Author</dt> <dd>sihui_liu@apple.com</dd>
<dt>Date</dt> <dd>2020-11-13 18:16:49 -0800 (Fri, 13 Nov 2020)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement basic permission check for SpeechRecognition
https://bugs.webkit.org/show_bug.cgi?id=218476
<rdar://problem/71222638>

Reviewed by Youenn Fablet.

Source/WebCore:

Tests: fast/speechrecognition/permission-error.html
       fast/speechrecognition/start-recognition-in-removed-iframe.html

* Modules/speech/SpeechRecognition.cpp:
(WebCore::SpeechRecognition::startRecognition):
* Modules/speech/SpeechRecognitionConnection.h:
* Modules/speech/SpeechRecognitionRequest.cpp:
(WebCore::SpeechRecognitionRequest::create): Deleted.
* Modules/speech/SpeechRecognitionRequest.h:
(WebCore::SpeechRecognitionRequest::clientOrigin const):
* Modules/speech/SpeechRecognitionRequestInfo.h:
(WebCore::SpeechRecognitionRequestInfo::encode const):
(WebCore::SpeechRecognitionRequestInfo::decode):
* Modules/speech/SpeechRecognitionUpdate.cpp:
(WebCore::SpeechRecognitionUpdate::create):
(WebCore::SpeechRecognitionUpdate::error const):
(WebCore::SpeechRecognitionUpdate::result const):
* Modules/speech/SpeechRecognitionUpdate.h:
* page/DummySpeechRecognitionProvider.h:

Source/WebKit:

Introduce SpeechRecognitionPermissionManager, which checks and requests speech recognition permissions before
we actually start capturing audio and perform recognition. SpeechRecognitionPermissionManager is per-page, like
SpeechRecognitionServer. The checks include:
1. Sandbox requirement for microphone
2. TCC check for microphone
3. TCC check for SFSpeechRecognizer
4. User permission on speech recognition for origin

Add a delegate function for requesting user permission. By default, user permission is not granted.

API test: WebKit2.SpeechRecognitionUserPermissionPersistence

* Headers.cmake:
* Shared/API/APIObject.h:
* Shared/API/c/WKBase.h:
* Sources.txt:
* SourcesCocoa.txt:
* UIProcess/API/APIUIClient.h:
(API::UIClient::decidePolicyForSpeechRecognitionPermissionRequest):
* UIProcess/API/C/WKAPICast.h:
* UIProcess/API/C/WKPage.cpp:
(WKPageSetPageUIClient):
* UIProcess/API/C/WKPageUIClient.h:
* UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp: Added.
(WKSpeechRecognitionPermissionCallbackGetTypeID):
(WKSpeechRecognitionPermissionCallbackComplete):
* UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h: Added.
* UIProcess/API/Cocoa/WKPreferences.mm:
(-[WKPreferences _speechRecognitionEnabled]):
(-[WKPreferences _setSpeechRecognitionEnabled:]):
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
* UIProcess/Cocoa/MediaPermissionUtilities.mm: Added.
(WebKit::checkSandboxRequirementForType):
(WebKit::checkUsageDescriptionStringForType):
(WebKit::checkUsageDescriptionStringForSpeechRecognition):
(WebKit::requestAVCaptureAccessForType):
(WebKit::checkAVCaptureAccessForType):
(WebKit::requestSpeechRecognitionAccess):
(WebKit::checkSpeechRecognitionServiceAccess):
* UIProcess/Cocoa/UIDelegate.h:
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::UIClient::decidePolicyForSpeechRecognitionPermissionRequest):
* UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm:
(WebKit::UserMediaPermissionRequestManagerProxy::permittedToCaptureAudio):
(WebKit::UserMediaPermissionRequestManagerProxy::permittedToCaptureVideo):
(WebKit::UserMediaPermissionRequestManagerProxy::requestSystemValidation):
(WebKit::requestAVCaptureAccessForMediaType): Deleted.
* UIProcess/Cocoa/WebProcessProxyCocoa.mm:
* UIProcess/MediaPermissionUtilities.h: Copied from Added.
* UIProcess/SpeechRecognitionPermissionManager.cpp: Added.
(WebKit::computeMicrophoneAccess):
(WebKit::computeSpeechRecognitionServiceAccess):
(WebKit::SpeechRecognitionPermissionManager::SpeechRecognitionPermissionManager):
(WebKit::SpeechRecognitionPermissionManager::~SpeechRecognitionPermissionManager):
(WebKit::SpeechRecognitionPermissionManager::request):
(WebKit::SpeechRecognitionPermissionManager::startNextRequest):
(WebKit::SpeechRecognitionPermissionManager::startProcessingRequest):
(WebKit::SpeechRecognitionPermissionManager::continueProcessingRequest):
(WebKit::SpeechRecognitionPermissionManager::completeCurrentRequest):
(WebKit::SpeechRecognitionPermissionManager::requestSpeechRecognitionServiceAccess):
(WebKit::SpeechRecognitionPermissionManager::requestMicrophoneAccess):
(WebKit::SpeechRecognitionPermissionManager::requestUserPermission):
* UIProcess/SpeechRecognitionPermissionManager.h: Added.
* UIProcess/SpeechRecognitionPermissionRequest.h: Added.
(WebKit::SpeechRecognitionPermissionRequest::create):
(WebKit::SpeechRecognitionPermissionRequest::complete):
(WebKit::SpeechRecognitionPermissionRequest::origin const):
(WebKit::SpeechRecognitionPermissionRequest::SpeechRecognitionPermissionRequest):
(WebKit::SpeechRecognitionPermissionCallback::create):
(WebKit::SpeechRecognitionPermissionCallback::complete):
(WebKit::SpeechRecognitionPermissionCallback::SpeechRecognitionPermissionCallback):
* UIProcess/SpeechRecognitionServer.cpp:
(WebKit::SpeechRecognitionServer::SpeechRecognitionServer):
(WebKit::SpeechRecognitionServer::start):
(WebKit::SpeechRecognitionServer::requestPermissionForRequest):
(WebKit::SpeechRecognitionServer::stop):
(WebKit::SpeechRecognitionServer::abort):
(WebKit::SpeechRecognitionServer::invalidate):
(WebKit::SpeechRecognitionServer::handleRequest):
(WebKit::SpeechRecognitionServer::stopRequest):
(WebKit::SpeechRecognitionServer::abortRequest):
(WebKit::SpeechRecognitionServer::sendUpdate):
(WebKit::SpeechRecognitionServer::processNextPendingRequestIfNeeded): Deleted.
(WebKit::SpeechRecognitionServer::removePendingRequest): Deleted.
(WebKit::SpeechRecognitionServer::startPocessingRequest): Deleted.
(WebKit::SpeechRecognitionServer::stopProcessingRequest): Deleted.
* UIProcess/SpeechRecognitionServer.h:
* UIProcess/SpeechRecognitionServer.messages.in:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didChangeMainDocument):
(WebKit::WebPageProxy::resetState):
(WebKit::WebPageProxy::requestSpeechRecognitionPermission):
* UIProcess/WebPageProxy.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::createSpeechRecognitionServer):
* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp:
(WebKit::WebSpeechRecognitionConnection::start):
(WebKit::WebSpeechRecognitionConnection::didReceiveUpdate):
* WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h:

Source/WTF:

* wtf/PlatformHave.h:

Tools:

* MiniBrowser/mac/Info.plist:
* MobileMiniBrowser/MobileMiniBrowser/Info.plist:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm: Added.
(-[SpeechRecognitionPermissionUIDelegate _webView:requestSpeechRecognitionPermissionForOrigin:decisionHandler:]):
(-[SpeechRecognitionMessageHandler userContentController:didReceiveScriptMessage:]):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html: Added.
* WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
* WebKitTestRunner/InjectedBundle/TestRunner.cpp:
(WTR::TestRunner::setIsSpeechRecognitionPermissionGranted):
* WebKitTestRunner/InjectedBundle/TestRunner.h:
* WebKitTestRunner/TestController.cpp:
(WTR::decidePolicyForSpeechRecognitionPermissionRequest):
(WTR::TestController::completeSpeechRecognitionPermissionCheck):
(WTR::TestController::setIsSpeechRecognitionPermissionGranted):
(WTR::TestController::createWebViewWithOptions):
(WTR::TestController::resetStateToConsistentValues):
* WebKitTestRunner/TestController.h:
* WebKitTestRunner/TestInvocation.cpp:
(WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):

LayoutTests:

* TestExpectations:
* fast/speechrecognition/permission-error-expected.txt: Added.
* fast/speechrecognition/permission-error.html: Added.
* fast/speechrecognition/resources/removed-iframe.html: Added.
* fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt: Added.
* fast/speechrecognition/start-recognition-in-removed-iframe.html: Added.
* platform/wk2/TestExpectations:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsplatformwk2TestExpectations">trunk/LayoutTests/platform/wk2/TestExpectations</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfPlatformHaveh">trunk/Source/WTF/wtf/PlatformHave.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitioncpp">trunk/Source/WebCore/Modules/speech/SpeechRecognition.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionConnectionh">trunk/Source/WebCore/Modules/speech/SpeechRecognitionConnection.h</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionRequestcpp">trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionRequesth">trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionRequestInfoh">trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequestInfo.h</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionUpdatecpp">trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.cpp</a></li>
<li><a href="#trunkSourceWebCoreModulesspeechSpeechRecognitionUpdateh">trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.h</a></li>
<li><a href="#trunkSourceWebCorepageDummySpeechRecognitionProviderh">trunk/Source/WebCore/page/DummySpeechRecognitionProvider.h</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitHeaderscmake">trunk/Source/WebKit/Headers.cmake</a></li>
<li><a href="#trunkSourceWebKitSharedAPIAPIObjecth">trunk/Source/WebKit/Shared/API/APIObject.h</a></li>
<li><a href="#trunkSourceWebKitSharedAPIcWKBaseh">trunk/Source/WebKit/Shared/API/c/WKBase.h</a></li>
<li><a href="#trunkSourceWebKitSourcestxt">trunk/Source/WebKit/Sources.txt</a></li>
<li><a href="#trunkSourceWebKitSourcesCocoatxt">trunk/Source/WebKit/SourcesCocoa.txt</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPIAPIUIClienth">trunk/Source/WebKit/UIProcess/API/APIUIClient.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKAPICasth">trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKPagecpp">trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKPageUIClienth">trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKPreferencesmm">trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKPreferencesPrivateh">trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICocoaWKUIDelegatePrivateh">trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaUIDelegateh">trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaUIDelegatemm">trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaUserMediaPermissionRequestManagerProxymm">trunk/Source/WebKit/UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaWebProcessProxyCocoamm">trunk/Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionServercpp">trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionServerh">trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionServermessagesin">trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.messages.in</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxycpp">trunk/Source/WebKit/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebPageProxyh">trunk/Source/WebKit/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessWebProcessProxycpp">trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp</a></li>
<li><a href="#trunkSourceWebKitWebKitxcodeprojprojectpbxproj">trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebCoreSupportWebSpeechRecognitionConnectioncpp">trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp</a></li>
<li><a href="#trunkSourceWebKitWebProcessWebCoreSupportWebSpeechRecognitionConnectionh">trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsMiniBrowsermacInfoplist">trunk/Tools/MiniBrowser/mac/Info.plist</a></li>
<li><a href="#trunkToolsMobileMiniBrowserMobileMiniBrowserInfoplist">trunk/Tools/MobileMiniBrowser/MobileMiniBrowser/Info.plist</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleBindingsTestRunneridl">trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleTestRunnercpp">trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerInjectedBundleTestRunnerh">trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestControllercpp">trunk/Tools/WebKitTestRunner/TestController.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestControllerh">trunk/Tools/WebKitTestRunner/TestController.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerTestInvocationcpp">trunk/Tools/WebKitTestRunner/TestInvocation.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastspeechrecognitionpermissionerrorexpectedtxt">trunk/LayoutTests/fast/speechrecognition/permission-error-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastspeechrecognitionpermissionerrorhtml">trunk/LayoutTests/fast/speechrecognition/permission-error.html</a></li>
<li>trunk/LayoutTests/fast/speechrecognition/resources/</li>
<li><a href="#trunkLayoutTestsfastspeechrecognitionresourcesremovediframehtml">trunk/LayoutTests/fast/speechrecognition/resources/removed-iframe.html</a></li>
<li><a href="#trunkLayoutTestsfastspeechrecognitionstartrecognitioninremovediframeexpectedtxt">trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastspeechrecognitionstartrecognitioninremovediframehtml">trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe.html</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKSpeechRecognitionPermissionCallbackcpp">trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessAPICWKSpeechRecognitionPermissionCallbackh">trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessCocoaMediaPermissionUtilitiesmm">trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessMediaPermissionUtilitiesh">trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionPermissionManagercpp">trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.cpp</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionPermissionManagerh">trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.h</a></li>
<li><a href="#trunkSourceWebKitUIProcessSpeechRecognitionPermissionRequesth">trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionRequest.h</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaSpeechRecognitionmm">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitCocoaspeechrecognitionuserpermissionpersistencehtml">trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog      2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/LayoutTests/ChangeLog 2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2020-11-13  Sihui Liu  <sihui_liu@apple.com>
+
+        Implement basic permission check for SpeechRecognition
+        https://bugs.webkit.org/show_bug.cgi?id=218476
+        <rdar://problem/71222638>
+
+        Reviewed by Youenn Fablet.
+
+        * TestExpectations:
+        * fast/speechrecognition/permission-error-expected.txt: Added.
+        * fast/speechrecognition/permission-error.html: Added.
+        * fast/speechrecognition/resources/removed-iframe.html: Added.
+        * fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt: Added.
+        * fast/speechrecognition/start-recognition-in-removed-iframe.html: Added.
+        * platform/wk2/TestExpectations:
+
</ins><span class="cx"> 2020-11-13  Ryan Haddad  <ryanhaddad@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, reverting r269776.
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/LayoutTests/TestExpectations  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -177,6 +177,7 @@
</span><span class="cx"> storage/indexeddb/IDBObject-leak.html [ Skip ]
</span><span class="cx"> fast/forms/call-text-did-change-in-text-field-when-typing.html [ Skip ]
</span><span class="cx"> http/tests/in-app-browser-privacy/ [ Skip ]
</span><ins>+fast/speechrecognition/permission-error.html [ Skip ]
</ins><span class="cx"> 
</span><span class="cx"> # Only partial support on Cocoa platforms.
</span><span class="cx"> imported/w3c/web-platform-tests/speech-api/ [ Skip ]
</span></span></pre></div>
<a id="trunkLayoutTestsfastspeechrecognitionpermissionerrorexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/speechrecognition/permission-error-expected.txt (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/speechrecognition/permission-error-expected.txt                           (rev 0)
+++ trunk/LayoutTests/fast/speechrecognition/permission-error-expected.txt      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+Verify that error event is fired when permission is denied.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS recognition = new SpeechRecognition() did not throw exception.
+PASS recognition.start() did not throw exception.
+PASS event.error is "not-allowed"
+PASS event.message is "Permission check failed"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastspeechrecognitionpermissionerrorhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/speechrecognition/permission-error.html (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/speechrecognition/permission-error.html                           (rev 0)
+++ trunk/LayoutTests/fast/speechrecognition/permission-error.html      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Verify that error event is fired when permission is denied.");
+
+if (window.testRunner) {
+    jsTestIsAsync = true;
+    testRunner.setIsSpeechRecognitionPermissionGranted(false);
+}
+
+shouldNotThrow("recognition = new SpeechRecognition()");
+shouldNotThrow("recognition.start()");
+recognition.onerror = (event) => {
+    shouldBeEqualToString("event.error", "not-allowed");
+    shouldBeEqualToString("event.message", "Permission check failed");
+
+    finishJSTest();
+}
+
+</script>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfastspeechrecognitionresourcesremovediframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/speechrecognition/resources/removed-iframe.html (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/speechrecognition/resources/removed-iframe.html                           (rev 0)
+++ trunk/LayoutTests/fast/speechrecognition/resources/removed-iframe.html      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<script>
+
+function startRecognition() {
+    recognition = new SpeechRecognition();
+    parent.removeFrame();
+    recognition.start();
+}
+
+</script>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsfastspeechrecognitionstartrecognitioninremovediframeexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe-expected.txt   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+Verify that process does not crash when starting recognition in a removed iframe.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS iframe.parentNode.removeChild(iframe) did not throw exception.
+PASS iframe.contentWindow.startRecognition() did not throw exception.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastspeechrecognitionstartrecognitioninremovediframehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe.html (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe.html                                (rev 0)
+++ trunk/LayoutTests/fast/speechrecognition/start-recognition-in-removed-iframe.html   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<body>
+<script src="../../resources/js-test.js"></script>
+<script>
+description("Verify that process does not crash when starting recognition in a removed iframe.");
+
+function test()
+{
+    iframe = document.getElementsByTagName('iframe')[0];
+    shouldNotThrow("iframe.contentWindow.startRecognition()"); 
+}
+
+function removeFrame()
+{
+    shouldNotThrow("iframe.parentNode.removeChild(iframe)");
+}
+
+window.addEventListener('load', test, false);
+</script>
+<iframe src="resources/removed-iframe.html"></iframe>
+</body>
+</html>
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkLayoutTestsplatformwk2TestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/wk2/TestExpectations (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/wk2/TestExpectations  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/LayoutTests/platform/wk2/TestExpectations     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -803,4 +803,5 @@
</span><span class="cx"> 
</span><span class="cx"> # WebKit2 only.
</span><span class="cx"> js/throw-large-string-oom.html [ Pass ]
</span><ins>+fast/speechrecognition/permission-error.html [ Pass ]
</ins><span class="cx"> fullscreen/full-screen-enter-while-exiting.html [ Pass ]
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WTF/ChangeLog  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2020-11-13  Sihui Liu  <sihui_liu@apple.com>
+
+        Implement basic permission check for SpeechRecognition
+        https://bugs.webkit.org/show_bug.cgi?id=218476
+        <rdar://problem/71222638>
+
+        Reviewed by Youenn Fablet.
+
+        * wtf/PlatformHave.h:
+
</ins><span class="cx"> 2020-11-13  Sam Weinig  <weinig@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Move some more WebKit and WebKitLegacy preferences bound to Settings to WebPreferences.yaml
</span></span></pre></div>
<a id="trunkSourceWTFwtfPlatformHaveh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/PlatformHave.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/PlatformHave.h      2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WTF/wtf/PlatformHave.h 2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -762,3 +762,11 @@
</span><span class="cx">     || (PLATFORM(APPLETV) && __TV_OS_VERSION_MIN_REQUIRED >= 140000)
</span><span class="cx"> #define HAVE_AVOUTPUTDEVICE_SPATIALAUDIO 1
</span><span class="cx"> #endif
</span><ins>+
+#if PLATFORM(IOS) || PLATFORM(MACCATALYST) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
+#define HAVE_SPEECHRECOGNIZER 1
+#endif
+
+#if PLATFORM(IOS) || PLATFORM(MACCATALYST) || PLATFORM(MAC)
+#define HAVE_AVCAPTUREDEVICE 1
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/ChangeLog      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2020-11-13  Sihui Liu  <sihui_liu@apple.com>
+
+        Implement basic permission check for SpeechRecognition
+        https://bugs.webkit.org/show_bug.cgi?id=218476
+        <rdar://problem/71222638>
+
+        Reviewed by Youenn Fablet.
+
+        Tests: fast/speechrecognition/permission-error.html
+               fast/speechrecognition/start-recognition-in-removed-iframe.html
+
+        * Modules/speech/SpeechRecognition.cpp:
+        (WebCore::SpeechRecognition::startRecognition):
+        * Modules/speech/SpeechRecognitionConnection.h:
+        * Modules/speech/SpeechRecognitionRequest.cpp:
+        (WebCore::SpeechRecognitionRequest::create): Deleted.
+        * Modules/speech/SpeechRecognitionRequest.h:
+        (WebCore::SpeechRecognitionRequest::clientOrigin const):
+        * Modules/speech/SpeechRecognitionRequestInfo.h:
+        (WebCore::SpeechRecognitionRequestInfo::encode const):
+        (WebCore::SpeechRecognitionRequestInfo::decode):
+        * Modules/speech/SpeechRecognitionUpdate.cpp:
+        (WebCore::SpeechRecognitionUpdate::create):
+        (WebCore::SpeechRecognitionUpdate::error const):
+        (WebCore::SpeechRecognitionUpdate::result const):
+        * Modules/speech/SpeechRecognitionUpdate.h:
+        * page/DummySpeechRecognitionProvider.h:
+
</ins><span class="cx"> 2020-11-13  Kate Cheney  <katherine_cheney@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Can't login to Microsoft Teams
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognition.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognition.cpp        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognition.cpp   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "SpeechRecognition.h"
</span><span class="cx"> 
</span><ins>+#include "ClientOrigin.h"
</ins><span class="cx"> #include "Document.h"
</span><span class="cx"> #include "EventNames.h"
</span><span class="cx"> #include "Page.h"
</span><span class="lines">@@ -69,7 +70,8 @@
</span><span class="cx">     if (!m_connection)
</span><span class="cx">         return Exception { UnknownError, "Recognition does not have a valid connection"_s };
</span><span class="cx"> 
</span><del>-    m_connection->start(identifier(), m_lang, m_continuous, m_interimResults, m_maxAlternatives);
</del><ins>+    auto& document = downcast<Document>(*scriptExecutionContext());
+    m_connection->start(identifier(), m_lang, m_continuous, m_interimResults, m_maxAlternatives, ClientOrigin { document.topOrigin().data(), document.securityOrigin().data() });
</ins><span class="cx">     m_state = State::Starting;
</span><span class="cx">     return { };
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionConnection.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionConnection.h        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionConnection.h   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -31,15 +31,16 @@
</span><span class="cx"> 
</span><span class="cx"> class SpeechRecognitionConnectionClient;
</span><span class="cx"> class SpeechRecognitionUpdate;
</span><ins>+struct ClientOrigin;
</ins><span class="cx"> 
</span><span class="cx"> class SpeechRecognitionConnection : public RefCounted<SpeechRecognitionConnection> {
</span><span class="cx"> public:
</span><span class="cx">     virtual ~SpeechRecognitionConnection() { }
</span><span class="cx">     virtual void registerClient(SpeechRecognitionConnectionClient&) = 0;
</span><del>-    virtual void start(SpeechRecognitionConnectionClientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives) = 0;
</del><ins>+    virtual void start(SpeechRecognitionConnectionClientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives, ClientOrigin&&) = 0;
</ins><span class="cx">     virtual void stop(SpeechRecognitionConnectionClientIdentifier) = 0;
</span><span class="cx">     virtual void abort(SpeechRecognitionConnectionClientIdentifier) = 0;
</span><del>-    virtual void didReceiveUpdate(const SpeechRecognitionUpdate&) = 0;
</del><ins>+    virtual void didReceiveUpdate(SpeechRecognitionUpdate&&) = 0;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionRequestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.cpp 2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.cpp    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -28,11 +28,6 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-Ref<SpeechRecognitionRequest> SpeechRecognitionRequest::create(SpeechRecognitionRequestInfo&& requestInfo)
-{
-    return adoptRef(*new SpeechRecognitionRequest(WTFMove(requestInfo)));
-}
-
</del><span class="cx"> SpeechRecognitionRequest::SpeechRecognitionRequest(SpeechRecognitionRequestInfo&& requestInfo)
</span><span class="cx">     : m_info(WTFMove(requestInfo))
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionRequesth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -30,9 +30,10 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-class SpeechRecognitionRequest : public RefCounted<SpeechRecognitionRequest> {
</del><ins>+class SpeechRecognitionRequest : public CanMakeWeakPtr<SpeechRecognitionRequest> {
+    WTF_MAKE_FAST_ALLOCATED;
</ins><span class="cx"> public:
</span><del>-    WEBCORE_EXPORT static Ref<SpeechRecognitionRequest> create(SpeechRecognitionRequestInfo&&);
</del><ins>+    WEBCORE_EXPORT explicit SpeechRecognitionRequest(SpeechRecognitionRequestInfo&&);
</ins><span class="cx"> 
</span><span class="cx">     SpeechRecognitionConnectionClientIdentifier clientIdentifier() const { return m_info.clientIdentifier; }
</span><span class="cx">     const String& lang() const { return m_info.lang; }
</span><span class="lines">@@ -39,10 +40,9 @@
</span><span class="cx">     bool continuous() const { return m_info.continuous;; }
</span><span class="cx">     bool interimResults() const { return m_info.interimResults; }
</span><span class="cx">     uint64_t maxAlternatives() const { return m_info.maxAlternatives; }
</span><ins>+    const ClientOrigin clientOrigin() const { return m_info.clientOrigin; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    explicit SpeechRecognitionRequest(SpeechRecognitionRequestInfo&&);
-
</del><span class="cx">     SpeechRecognitionRequestInfo m_info;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionRequestInfoh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequestInfo.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequestInfo.h       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequestInfo.h  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -25,6 +25,7 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include "ClientOrigin.h"
</ins><span class="cx"> #include "SpeechRecognitionConnectionClientIdentifier.h"
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -35,6 +36,7 @@
</span><span class="cx">     bool continuous { false };
</span><span class="cx">     bool interimResults { false };
</span><span class="cx">     uint64_t maxAlternatives { 1 };
</span><ins>+    ClientOrigin clientOrigin;
</ins><span class="cx"> 
</span><span class="cx">     template<class Encoder> void encode(Encoder&) const;
</span><span class="cx">     template<class Decoder> static Optional<SpeechRecognitionRequestInfo> decode(Decoder&);
</span><span class="lines">@@ -43,7 +45,7 @@
</span><span class="cx"> template<class Encoder>
</span><span class="cx"> void SpeechRecognitionRequestInfo::encode(Encoder& encoder) const
</span><span class="cx"> {
</span><del>-    encoder << clientIdentifier << lang << continuous << interimResults << maxAlternatives;
</del><ins>+    encoder << clientIdentifier << lang << continuous << interimResults << maxAlternatives << clientOrigin;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template<class Decoder>
</span><span class="lines">@@ -74,12 +76,18 @@
</span><span class="cx">     if (!maxAlternatives)
</span><span class="cx">         return WTF::nullopt;
</span><span class="cx"> 
</span><ins>+    Optional<ClientOrigin> clientOrigin;
+    decoder >> clientOrigin;
+    if (!clientOrigin)
+        return WTF::nullopt;
+
</ins><span class="cx">     return {{
</span><span class="cx">         WTFMove(*clientIdentifier),
</span><span class="cx">         WTFMove(*lang),
</span><span class="cx">         WTFMove(*continuous),
</span><span class="cx">         WTFMove(*interimResults),
</span><del>-        WTFMove(*maxAlternatives)
</del><ins>+        WTFMove(*maxAlternatives),
+        WTFMove(*clientOrigin)
</ins><span class="cx">     }};
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionUpdatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.cpp  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.cpp     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx"> 
</span><span class="cx"> SpeechRecognitionUpdate SpeechRecognitionUpdate::create(SpeechRecognitionConnectionClientIdentifier clientIdentifier, SpeechRecognitionUpdateType type)
</span><span class="cx"> {
</span><del>-    return SpeechRecognitionUpdate { clientIdentifier, type };
</del><ins>+    return SpeechRecognitionUpdate { clientIdentifier, type, WTF::Monostate() };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> SpeechRecognitionUpdate SpeechRecognitionUpdate::createError(SpeechRecognitionConnectionClientIdentifier clientIdentifier, const SpeechRecognitionError& error)
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx"> SpeechRecognitionError SpeechRecognitionUpdate::error() const
</span><span class="cx"> {
</span><span class="cx">     return WTF::switchOn(m_content,
</span><del>-        [] (SpeechRecognitionError& error) { return error; },
</del><ins>+        [] (const SpeechRecognitionError& error) { return error; },
</ins><span class="cx">         [] (const auto&) { return SpeechRecognitionError(); }
</span><span class="cx">     );
</span><span class="cx"> }
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx"> Vector<SpeechRecognitionResultData> SpeechRecognitionUpdate::result() const
</span><span class="cx"> {
</span><span class="cx">     return WTF::switchOn(m_content,
</span><del>-        [] (Vector<SpeechRecognitionResultData>& data) { return data; },
</del><ins>+        [] (const Vector<SpeechRecognitionResultData>& data) { return data; },
</ins><span class="cx">         [] (const auto&) { return Vector<SpeechRecognitionResultData> { }; }
</span><span class="cx">     );
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreModulesspeechSpeechRecognitionUpdateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.h    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/Modules/speech/SpeechRecognitionUpdate.h       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -52,8 +52,8 @@
</span><span class="cx"> class SpeechRecognitionUpdate {
</span><span class="cx"> public:
</span><span class="cx">     WEBCORE_EXPORT static SpeechRecognitionUpdate create(SpeechRecognitionConnectionClientIdentifier, SpeechRecognitionUpdateType);
</span><del>-    static SpeechRecognitionUpdate createError(SpeechRecognitionConnectionClientIdentifier, const SpeechRecognitionError&);
-    static SpeechRecognitionUpdate createResult(SpeechRecognitionConnectionClientIdentifier, const Vector<SpeechRecognitionResultData>&);
</del><ins>+    WEBCORE_EXPORT static SpeechRecognitionUpdate createError(SpeechRecognitionConnectionClientIdentifier, const SpeechRecognitionError&);
+    WEBCORE_EXPORT static SpeechRecognitionUpdate createResult(SpeechRecognitionConnectionClientIdentifier, const Vector<SpeechRecognitionResultData>&);
</ins><span class="cx"> 
</span><span class="cx">     SpeechRecognitionConnectionClientIdentifier clientIdentifier() const { return m_clientIdentifier; }
</span><span class="cx">     SpeechRecognitionUpdateType type() const { return m_type; }
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     using Content = Variant<WTF::Monostate, SpeechRecognitionError, Vector<SpeechRecognitionResultData>>;
</span><del>-    WEBCORE_EXPORT explicit SpeechRecognitionUpdate(SpeechRecognitionConnectionClientIdentifier, SpeechRecognitionUpdateType, Content = WTF::Monostate());
</del><ins>+    WEBCORE_EXPORT SpeechRecognitionUpdate(SpeechRecognitionConnectionClientIdentifier, SpeechRecognitionUpdateType, Content);
</ins><span class="cx"> 
</span><span class="cx">     SpeechRecognitionConnectionClientIdentifier m_clientIdentifier;
</span><span class="cx">     SpeechRecognitionUpdateType m_type;
</span></span></pre></div>
<a id="trunkSourceWebCorepageDummySpeechRecognitionProviderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DummySpeechRecognitionProvider.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DummySpeechRecognitionProvider.h       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebCore/page/DummySpeechRecognitionProvider.h  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -39,10 +39,10 @@
</span><span class="cx">             return adoptRef(*new DummySpeechRecognitionConnection());
</span><span class="cx">         }
</span><span class="cx">         void registerClient(SpeechRecognitionConnectionClient&) final { }
</span><del>-        void start(SpeechRecognitionConnectionClientIdentifier, const String&, bool, bool, uint64_t) final { }
</del><ins>+        void start(SpeechRecognitionConnectionClientIdentifier, const String&, bool, bool, uint64_t, ClientOrigin&&) final { }
</ins><span class="cx">         void stop(SpeechRecognitionConnectionClientIdentifier) final { }
</span><span class="cx">         void abort(SpeechRecognitionConnectionClientIdentifier) final { }
</span><del>-        void didReceiveUpdate(const SpeechRecognitionUpdate&) final { }
</del><ins>+        void didReceiveUpdate(SpeechRecognitionUpdate&&) final { }
</ins><span class="cx">     };
</span><span class="cx">     DummySpeechRecognitionProvider() = default;
</span><span class="cx">     SpeechRecognitionConnection& speechRecognitionConnection()
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/ChangeLog       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1,3 +1,113 @@
</span><ins>+2020-11-13  Sihui Liu  <sihui_liu@apple.com>
+
+        Implement basic permission check for SpeechRecognition
+        https://bugs.webkit.org/show_bug.cgi?id=218476
+        <rdar://problem/71222638>
+
+        Reviewed by Youenn Fablet.
+
+        Introduce SpeechRecognitionPermissionManager, which checks and requests speech recognition permissions before 
+        we actually start capturing audio and perform recognition. SpeechRecognitionPermissionManager is per-page, like
+        SpeechRecognitionServer. The checks include:
+        1. Sandbox requirement for microphone
+        2. TCC check for microphone
+        3. TCC check for SFSpeechRecognizer
+        4. User permission on speech recognition for origin
+
+        Add a delegate function for requesting user permission. By default, user permission is not granted.
+
+        API test: WebKit2.SpeechRecognitionUserPermissionPersistence
+
+        * Headers.cmake:
+        * Shared/API/APIObject.h:
+        * Shared/API/c/WKBase.h:
+        * Sources.txt:
+        * SourcesCocoa.txt:
+        * UIProcess/API/APIUIClient.h:
+        (API::UIClient::decidePolicyForSpeechRecognitionPermissionRequest):
+        * UIProcess/API/C/WKAPICast.h:
+        * UIProcess/API/C/WKPage.cpp:
+        (WKPageSetPageUIClient):
+        * UIProcess/API/C/WKPageUIClient.h:
+        * UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp: Added.
+        (WKSpeechRecognitionPermissionCallbackGetTypeID):
+        (WKSpeechRecognitionPermissionCallbackComplete):
+        * UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h: Added.
+        * UIProcess/API/Cocoa/WKPreferences.mm:
+        (-[WKPreferences _speechRecognitionEnabled]):
+        (-[WKPreferences _setSpeechRecognitionEnabled:]):
+        * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+        * UIProcess/Cocoa/MediaPermissionUtilities.mm: Added.
+        (WebKit::checkSandboxRequirementForType):
+        (WebKit::checkUsageDescriptionStringForType):
+        (WebKit::checkUsageDescriptionStringForSpeechRecognition):
+        (WebKit::requestAVCaptureAccessForType):
+        (WebKit::checkAVCaptureAccessForType):
+        (WebKit::requestSpeechRecognitionAccess):
+        (WebKit::checkSpeechRecognitionServiceAccess):
+        * UIProcess/Cocoa/UIDelegate.h:
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::UIClient::decidePolicyForSpeechRecognitionPermissionRequest):
+        * UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm:
+        (WebKit::UserMediaPermissionRequestManagerProxy::permittedToCaptureAudio):
+        (WebKit::UserMediaPermissionRequestManagerProxy::permittedToCaptureVideo):
+        (WebKit::UserMediaPermissionRequestManagerProxy::requestSystemValidation):
+        (WebKit::requestAVCaptureAccessForMediaType): Deleted.
+        * UIProcess/Cocoa/WebProcessProxyCocoa.mm:
+        * UIProcess/MediaPermissionUtilities.h: Copied from Added.
+        * UIProcess/SpeechRecognitionPermissionManager.cpp: Added.
+        (WebKit::computeMicrophoneAccess):
+        (WebKit::computeSpeechRecognitionServiceAccess):
+        (WebKit::SpeechRecognitionPermissionManager::SpeechRecognitionPermissionManager):
+        (WebKit::SpeechRecognitionPermissionManager::~SpeechRecognitionPermissionManager):
+        (WebKit::SpeechRecognitionPermissionManager::request):
+        (WebKit::SpeechRecognitionPermissionManager::startNextRequest):
+        (WebKit::SpeechRecognitionPermissionManager::startProcessingRequest):
+        (WebKit::SpeechRecognitionPermissionManager::continueProcessingRequest):
+        (WebKit::SpeechRecognitionPermissionManager::completeCurrentRequest):
+        (WebKit::SpeechRecognitionPermissionManager::requestSpeechRecognitionServiceAccess):
+        (WebKit::SpeechRecognitionPermissionManager::requestMicrophoneAccess):
+        (WebKit::SpeechRecognitionPermissionManager::requestUserPermission):
+        * UIProcess/SpeechRecognitionPermissionManager.h: Added.
+        * UIProcess/SpeechRecognitionPermissionRequest.h: Added.
+        (WebKit::SpeechRecognitionPermissionRequest::create):
+        (WebKit::SpeechRecognitionPermissionRequest::complete):
+        (WebKit::SpeechRecognitionPermissionRequest::origin const):
+        (WebKit::SpeechRecognitionPermissionRequest::SpeechRecognitionPermissionRequest):
+        (WebKit::SpeechRecognitionPermissionCallback::create):
+        (WebKit::SpeechRecognitionPermissionCallback::complete):
+        (WebKit::SpeechRecognitionPermissionCallback::SpeechRecognitionPermissionCallback):
+        * UIProcess/SpeechRecognitionServer.cpp:
+        (WebKit::SpeechRecognitionServer::SpeechRecognitionServer):
+        (WebKit::SpeechRecognitionServer::start):
+        (WebKit::SpeechRecognitionServer::requestPermissionForRequest):
+        (WebKit::SpeechRecognitionServer::stop):
+        (WebKit::SpeechRecognitionServer::abort):
+        (WebKit::SpeechRecognitionServer::invalidate):
+        (WebKit::SpeechRecognitionServer::handleRequest):
+        (WebKit::SpeechRecognitionServer::stopRequest):
+        (WebKit::SpeechRecognitionServer::abortRequest):
+        (WebKit::SpeechRecognitionServer::sendUpdate):
+        (WebKit::SpeechRecognitionServer::processNextPendingRequestIfNeeded): Deleted.
+        (WebKit::SpeechRecognitionServer::removePendingRequest): Deleted.
+        (WebKit::SpeechRecognitionServer::startPocessingRequest): Deleted.
+        (WebKit::SpeechRecognitionServer::stopProcessingRequest): Deleted.
+        * UIProcess/SpeechRecognitionServer.h:
+        * UIProcess/SpeechRecognitionServer.messages.in:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didChangeMainDocument):
+        (WebKit::WebPageProxy::resetState):
+        (WebKit::WebPageProxy::requestSpeechRecognitionPermission):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::createSpeechRecognitionServer):
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp:
+        (WebKit::WebSpeechRecognitionConnection::start):
+        (WebKit::WebSpeechRecognitionConnection::didReceiveUpdate):
+        * WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h:
+
</ins><span class="cx"> 2020-11-13  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [GPUProcess] Add basic GPUProcess crash handling for canvas
</span></span></pre></div>
<a id="trunkSourceWebKitHeaderscmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Headers.cmake (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Headers.cmake        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/Headers.cmake   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx">     UIProcess/API/C/WKProtectionSpaceTypes.h
</span><span class="cx">     UIProcess/API/C/WKResourceCacheManager.h
</span><span class="cx">     UIProcess/API/C/WKSessionStateRef.h
</span><ins>+    UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h
</ins><span class="cx">     UIProcess/API/C/WKTestingSupport.h
</span><span class="cx">     UIProcess/API/C/WKTextChecker.h
</span><span class="cx">     UIProcess/API/C/WKUserContentControllerRef.h
</span></span></pre></div>
<a id="trunkSourceWebKitSharedAPIAPIObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/API/APIObject.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Shared/API/APIObject.h       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/Shared/API/APIObject.h  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -168,6 +168,7 @@
</span><span class="cx">         RunJavaScriptAlertResultListener,
</span><span class="cx">         RunJavaScriptConfirmResultListener,
</span><span class="cx">         RunJavaScriptPromptResultListener,
</span><ins>+        SpeechRecognitionPermissionCallback,
</ins><span class="cx">         TextChecker,
</span><span class="cx">         URLSchemeTask,
</span><span class="cx">         UserContentController,
</span><span class="lines">@@ -416,6 +417,7 @@
</span><span class="cx">         API::Object::Type::RunJavaScriptAlertResultListener,
</span><span class="cx">         API::Object::Type::RunJavaScriptConfirmResultListener,
</span><span class="cx">         API::Object::Type::RunJavaScriptPromptResultListener,
</span><ins>+        API::Object::Type::SpeechRecognitionPermissionCallback,
</ins><span class="cx">         API::Object::Type::TextChecker,
</span><span class="cx">         API::Object::Type::URLSchemeTask,
</span><span class="cx">         API::Object::Type::UserContentController,
</span></span></pre></div>
<a id="trunkSourceWebKitSharedAPIcWKBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Shared/API/c/WKBase.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Shared/API/c/WKBase.h        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/Shared/API/c/WKBase.h   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -141,6 +141,7 @@
</span><span class="cx"> typedef const struct OpaqueWKWebsiteDataStore* WKWebsiteDataStoreRef;
</span><span class="cx"> typedef const struct OpaqueWKWebsitePolicies* WKWebsitePoliciesRef;
</span><span class="cx"> typedef const struct OpaqueWKWindowFeatures* WKWindowFeaturesRef;
</span><ins>+typedef const struct OpaqueWKSpeechRecognitionPermissionCallback* WKSpeechRecognitionPermissionCallbackRef;
</ins><span class="cx"> 
</span><span class="cx"> /* WebKit2 Bundle types */
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitSourcestxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/Sources.txt (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/Sources.txt  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/Sources.txt     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -291,6 +291,7 @@
</span><span class="cx"> UIProcess/SpeechRecognitionServer.cpp
</span><span class="cx"> UIProcess/SuspendedPageProxy.cpp
</span><span class="cx"> UIProcess/SystemPreviewController.cpp
</span><ins>+UIProcess/SpeechRecognitionPermissionManager.cpp
</ins><span class="cx"> UIProcess/TextChecker.cpp
</span><span class="cx"> UIProcess/TextCheckerCompletion.cpp
</span><span class="cx"> UIProcess/UserMediaPermissionCheckProxy.cpp
</span><span class="lines">@@ -404,6 +405,7 @@
</span><span class="cx"> UIProcess/API/C/WKProtectionSpace.cpp
</span><span class="cx"> UIProcess/API/C/WKResourceCacheManager.cpp
</span><span class="cx"> UIProcess/API/C/WKSessionStateRef.cpp
</span><ins>+UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp
</ins><span class="cx"> UIProcess/API/C/WKTextChecker.cpp
</span><span class="cx"> UIProcess/API/C/WKUserContentControllerRef.cpp
</span><span class="cx"> UIProcess/API/C/WKUserContentExtensionStoreRef.cpp
</span></span></pre></div>
<a id="trunkSourceWebKitSourcesCocoatxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/SourcesCocoa.txt (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/SourcesCocoa.txt     2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/SourcesCocoa.txt        2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -374,6 +374,7 @@
</span><span class="cx"> UIProcess/Cocoa/IconLoadingDelegate.mm
</span><span class="cx"> UIProcess/Cocoa/LegacyCustomProtocolManagerClient.mm
</span><span class="cx"> UIProcess/Cocoa/MediaUtilities.mm
</span><ins>+UIProcess/Cocoa/MediaPermissionUtilities.mm
</ins><span class="cx"> UIProcess/Cocoa/NavigationState.mm
</span><span class="cx"> UIProcess/Cocoa/PageClientImplCocoa.mm
</span><span class="cx"> UIProcess/Cocoa/PlaybackSessionManagerProxy.mm
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPIAPIUIClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/APIUIClient.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/APIUIClient.h  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/APIUIClient.h     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -202,6 +202,7 @@
</span><span class="cx">         return API::InspectorConfiguration::create();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    virtual void decidePolicyForSpeechRecognitionPermissionRequest(WebKit::WebPageProxy&, API::SecurityOrigin&, CompletionHandler<void(bool)>&& completionHandler) { completionHandler(false); }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace API
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKAPICasth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx"> class DownloadProxy;
</span><span class="cx"> class GeolocationPermissionRequest;
</span><span class="cx"> class NotificationPermissionRequest;
</span><ins>+class SpeechRecognitionPermissionCallback;
</ins><span class="cx"> class UserMediaPermissionCheckProxy;
</span><span class="cx"> class UserMediaPermissionRequestProxy;
</span><span class="cx"> class WebBackForwardList;
</span><span class="lines">@@ -152,6 +153,7 @@
</span><span class="cx"> WK_ADD_API_MAPPING(WKProtectionSpaceRef, WebProtectionSpace)
</span><span class="cx"> WK_ADD_API_MAPPING(WKResourceLoadStatisticsManagerRef, WebResourceLoadStatisticsManager)
</span><span class="cx"> WK_ADD_API_MAPPING(WKSessionStateRef, API::SessionState)
</span><ins>+WK_ADD_API_MAPPING(WKSpeechRecognitionPermissionCallbackRef, SpeechRecognitionPermissionCallback)
</ins><span class="cx"> WK_ADD_API_MAPPING(WKTextCheckerRef, WebTextChecker)
</span><span class="cx"> WK_ADD_API_MAPPING(WKUserContentControllerRef, WebUserContentControllerProxy)
</span><span class="cx"> WK_ADD_API_MAPPING(WKUserContentExtensionStoreRef, API::ContentRuleListStore)
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx"> #include "PageClient.h"
</span><span class="cx"> #include "PluginInformation.h"
</span><span class="cx"> #include "PrintInfo.h"
</span><ins>+#include "SpeechRecognitionPermissionRequest.h"
</ins><span class="cx"> #include "WKAPICast.h"
</span><span class="cx"> #include "WKPagePolicyClientInternal.h"
</span><span class="cx"> #include "WKPageRenderingProgressEventsInternal.h"
</span><span class="lines">@@ -115,7 +116,7 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template<> struct ClientTraits<WKPageUIClientBase> {
</span><del>-    typedef std::tuple<WKPageUIClientV0, WKPageUIClientV1, WKPageUIClientV2, WKPageUIClientV3, WKPageUIClientV4, WKPageUIClientV5, WKPageUIClientV6, WKPageUIClientV7, WKPageUIClientV8, WKPageUIClientV9, WKPageUIClientV10, WKPageUIClientV11, WKPageUIClientV12, WKPageUIClientV13, WKPageUIClientV14> Versions;
</del><ins>+    typedef std::tuple<WKPageUIClientV0, WKPageUIClientV1, WKPageUIClientV2, WKPageUIClientV3, WKPageUIClientV4, WKPageUIClientV5, WKPageUIClientV6, WKPageUIClientV7, WKPageUIClientV8, WKPageUIClientV9, WKPageUIClientV10, WKPageUIClientV11, WKPageUIClientV12, WKPageUIClientV13, WKPageUIClientV14, WKPageUIClientV15> Versions;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CONTEXT_MENUS)
</span><span class="lines">@@ -2110,6 +2111,13 @@
</span><span class="cx">             completionHandler(WebKit::WebAuthenticationPanelResult::Presented);
</span><span class="cx">         }
</span><span class="cx"> #endif
</span><ins>+        void decidePolicyForSpeechRecognitionPermissionRequest(WebPageProxy& page, API::SecurityOrigin& origin, CompletionHandler<void(bool)>&& completionHandler) final
+        {
+            if (!m_client.decidePolicyForSpeechRecognitionPermissionRequest)
+                return;
+
+            m_client.decidePolicyForSpeechRecognitionPermissionRequest(toAPI(&page), toAPI(&origin), toAPI(SpeechRecognitionPermissionCallback::create(WTFMove(completionHandler)).ptr()));
+        }
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     toImpl(pageRef)->setUIClient(makeUnique<UIClient>(wkClient));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKPageUIClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h     2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/C/WKPageUIClient.h        2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -136,6 +136,7 @@
</span><span class="cx"> typedef bool (*WKPageShouldAllowDeviceOrientationAndMotionAccessCallback)(WKPageRef page, WKSecurityOriginRef securityOrigin, const void *clientInfo);
</span><span class="cx"> 
</span><span class="cx"> typedef void (*WKPageRunWebAuthenticationPanelCallback)();
</span><ins>+typedef void (*WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback)(WKPageRef page, WKSecurityOriginRef topOrigin, WKSpeechRecognitionPermissionCallbackRef callback);
</ins><span class="cx"> 
</span><span class="cx"> // Deprecated
</span><span class="cx"> typedef WKPageRef (*WKPageCreateNewPageCallback_deprecatedForUseWithV0)(WKPageRef page, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton mouseButton, const void *clientInfo);
</span><span class="lines">@@ -1353,6 +1354,117 @@
</span><span class="cx">     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
</span><span class="cx"> } WKPageUIClientV14;
</span><span class="cx"> 
</span><ins>+typedef struct WKPageUIClientV15 {
+    WKPageUIClientBase                                                  base;
+
+    // Version 0.
+    WKPageCreateNewPageCallback_deprecatedForUseWithV0                  createNewPage_deprecatedForUseWithV0;
+    WKPageUIClientCallback                                              showPage;
+    WKPageUIClientCallback                                              close;
+    WKPageTakeFocusCallback                                             takeFocus;
+    WKPageFocusCallback                                                 focus;
+    WKPageUnfocusCallback                                               unfocus;
+    WKPageRunJavaScriptAlertCallback_deprecatedForUseWithV0             runJavaScriptAlert_deprecatedForUseWithV0;
+    WKPageRunJavaScriptConfirmCallback_deprecatedForUseWithV0           runJavaScriptConfirm_deprecatedForUseWithV0;
+    WKPageRunJavaScriptPromptCallback_deprecatedForUseWithV0            runJavaScriptPrompt_deprecatedForUseWithV0;
+    WKPageSetStatusTextCallback                                         setStatusText;
+    WKPageMouseDidMoveOverElementCallback_deprecatedForUseWithV0        mouseDidMoveOverElement_deprecatedForUseWithV0;
+    WKPageMissingPluginButtonClickedCallback_deprecatedForUseWithV0     missingPluginButtonClicked_deprecatedForUseWithV0;
+    WKPageDidNotHandleKeyEventCallback                                  didNotHandleKeyEvent;
+    WKPageDidNotHandleWheelEventCallback                                didNotHandleWheelEvent;
+    WKPageGetToolbarsAreVisibleCallback                                 toolbarsAreVisible;
+    WKPageSetToolbarsAreVisibleCallback                                 setToolbarsAreVisible;
+    WKPageGetMenuBarIsVisibleCallback                                   menuBarIsVisible;
+    WKPageSetMenuBarIsVisibleCallback                                   setMenuBarIsVisible;
+    WKPageGetStatusBarIsVisibleCallback                                 statusBarIsVisible;
+    WKPageSetStatusBarIsVisibleCallback                                 setStatusBarIsVisible;
+    WKPageGetIsResizableCallback                                        isResizable;
+    WKPageSetIsResizableCallback                                        setIsResizable;
+    WKPageGetWindowFrameCallback                                        getWindowFrame;
+    WKPageSetWindowFrameCallback                                        setWindowFrame;
+    WKPageRunBeforeUnloadConfirmPanelCallback_deprecatedForUseWithV6    runBeforeUnloadConfirmPanel_deprecatedForUseWithV6;
+    WKPageUIClientCallback                                              didDraw;
+    WKPageUIClientCallback                                              pageDidScroll;
+    WKPageExceededDatabaseQuotaCallback                                 exceededDatabaseQuota;
+    WKPageRunOpenPanelCallback                                          runOpenPanel;
+    WKPageDecidePolicyForGeolocationPermissionRequestCallback           decidePolicyForGeolocationPermissionRequest;
+    WKPageHeaderHeightCallback                                          headerHeight;
+    WKPageFooterHeightCallback                                          footerHeight;
+    WKPageDrawHeaderCallback                                            drawHeader;
+    WKPageDrawFooterCallback                                            drawFooter;
+    WKPagePrintFrameCallback                                            printFrame;
+    WKPageUIClientCallback                                              runModal;
+    void*                                                               unused1; // Used to be didCompleteRubberBandForMainFrame
+    WKPageSaveDataToFileInDownloadsFolderCallback                       saveDataToFileInDownloadsFolder;
+    void*                                                               shouldInterruptJavaScript_unavailable;
+
+    // Version 1.
+    WKPageCreateNewPageCallback_deprecatedForUseWithV1                  createNewPage_deprecatedForUseWithV1;
+    WKPageMouseDidMoveOverElementCallback                               mouseDidMoveOverElement;
+    WKPageDecidePolicyForNotificationPermissionRequestCallback          decidePolicyForNotificationPermissionRequest;
+    WKPageUnavailablePluginButtonClickedCallback_deprecatedForUseWithV1 unavailablePluginButtonClicked_deprecatedForUseWithV1;
+
+    // Version 2.
+    WKPageShowColorPickerCallback                                       showColorPicker;
+    WKPageHideColorPickerCallback                                       hideColorPicker;
+    WKPageUnavailablePluginButtonClickedCallback                        unavailablePluginButtonClicked;
+
+    // Version 3.
+    WKPagePinnedStateDidChangeCallback                                  pinnedStateDidChange;
+
+    // Version 4.
+    void*                                                               unused2; // Used to be didBeginTrackingPotentialLongMousePress.
+    void*                                                               unused3; // Used to be didRecognizeLongMousePress.
+    void*                                                               unused4; // Used to be didCancelTrackingPotentialLongMousePress.
+    WKPageIsPlayingAudioDidChangeCallback                               isPlayingAudioDidChange;
+
+    // Version 5.
+    WKPageDecidePolicyForUserMediaPermissionRequestCallback             decidePolicyForUserMediaPermissionRequest;
+    WKPageDidClickAutoFillButtonCallback                                didClickAutoFillButton;
+    WKPageRunJavaScriptAlertCallback_deprecatedForUseWithV5             runJavaScriptAlert_deprecatedForUseWithV5;
+    WKPageRunJavaScriptConfirmCallback_deprecatedForUseWithV5           runJavaScriptConfirm_deprecatedForUseWithV5;
+    WKPageRunJavaScriptPromptCallback_deprecatedForUseWithV5            runJavaScriptPrompt_deprecatedForUseWithV5;
+    void*                                                               unused5; // Used to be mediaSessionMetadataDidChange.
+
+    // Version 6.
+    WKPageCreateNewPageCallback                                         createNewPage;
+    WKPageRunJavaScriptAlertCallback                                    runJavaScriptAlert;
+    WKPageRunJavaScriptConfirmCallback                                  runJavaScriptConfirm;
+    WKPageRunJavaScriptPromptCallback                                   runJavaScriptPrompt;
+    WKCheckUserMediaPermissionCallback                                  checkUserMediaPermissionForOrigin;
+
+    // Version 7.
+    WKPageRunBeforeUnloadConfirmPanelCallback                           runBeforeUnloadConfirmPanel;
+    WKFullscreenMayReturnToInlineCallback                               fullscreenMayReturnToInline;
+
+    // Version 8.
+    WKRequestPointerLockCallback                                        requestPointerLock;
+    WKDidLosePointerLockCallback                                        didLosePointerLock;
+
+    // Version 9.
+    WKHandleAutoplayEventCallback                                       handleAutoplayEvent;
+
+    // Version 10.
+    WKHasVideoInPictureInPictureDidChangeCallback                       hasVideoInPictureInPictureDidChange;
+    WKDidExceedBackgroundResourceLimitWhileInForegroundCallback         didExceedBackgroundResourceLimitWhileInForeground;
+
+    // Version 11.
+    WKPageDidResignInputElementStrongPasswordAppearanceCallback         didResignInputElementStrongPasswordAppearance;
+
+    // Version 12.
+    WKPageRequestStorageAccessConfirmCallback                           requestStorageAccessConfirm;
+
+    // Version 13.
+    WKPageShouldAllowDeviceOrientationAndMotionAccessCallback           shouldAllowDeviceOrientationAndMotionAccess;
+
+    // Version 14.
+    WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+
+    // Version 15.
+    WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
+    
+} WKPageUIClientV15;
+
</ins><span class="cx"> #ifdef __cplusplus
</span><span class="cx"> }
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKSpeechRecognitionPermissionCallbackcppfromrev269809trunkSourceWebCoreModulesspeechSpeechRecognitionRequestcpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp (from rev 269809, trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.cpp) (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp                            (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.cpp       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+/*
+ * Copyright (C) 2020 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 "config.h"
+#include "WKSpeechRecognitionPermissionCallback.h"
+
+#include "SpeechRecognitionPermissionRequest.h"
+#include "WKAPICast.h"
+
+using namespace WebKit;
+
+WKTypeID WKSpeechRecognitionPermissionCallbackGetTypeID()
+{
+    return toAPI(SpeechRecognitionPermissionCallback::APIType);
+}
+
+void WKSpeechRecognitionPermissionCallbackComplete(WKSpeechRecognitionPermissionCallbackRef speechRecognitionPermissionCallback, bool granted)
+{
+    return toImpl(speechRecognitionPermissionCallback)->complete(granted);
+}
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICWKSpeechRecognitionPermissionCallbackhfromrev269809trunkSourceWebKitUIProcessSpeechRecognitionServermessagesin"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h (from rev 269809, trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.messages.in) (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h                              (rev 0)
+++ trunk/Source/WebKit/UIProcess/API/C/WKSpeechRecognitionPermissionCallback.h 2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+/*
+ * Copyright (C) 2020 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
+
+#include <WebKit/WKBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WK_EXPORT WKTypeID WKSpeechRecognitionPermissionCallbackGetTypeID(void);
+
+WK_EXPORT void WKSpeechRecognitionPermissionCallbackComplete(WKSpeechRecognitionPermissionCallbackRef speechRecognitionPermissionCallback, bool granted);
+
+#ifdef __cplusplus
+}
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKPreferencesmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm 2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1436,6 +1436,16 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (BOOL)_speechRecognitionEnabled
+{
+    return _preferences->speechRecognitionEnabled();
+}
+
+- (void)_setSpeechRecognitionEnabled:(BOOL)speechRecognitionEnabled
+{
+    _preferences->setSpeechRecognitionEnabled(speechRecognitionEnabled);
+}
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKPreferencesPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -161,6 +161,7 @@
</span><span class="cx"> @property (nonatomic, setter=_setRequestAnimationFrameEnabled:) BOOL _requestAnimationFrameEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
</span><span class="cx"> @property (nonatomic, setter=_setServiceWorkerEntitlementDisabledForTesting:) BOOL _serviceWorkerEntitlementDisabledForTesting WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
</span><span class="cx"> @property (nonatomic, setter=_setAccessibilityIsolatedTreeEnabled:) BOOL _accessibilityIsolatedTreeEnabled WK_API_AVAILABLE(macos(10.16));
</span><ins>+@property (nonatomic, setter=_setSpeechRecognitionEnabled:) BOOL _speechRecognitionEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
</ins><span class="cx"> 
</span><span class="cx"> #if !TARGET_OS_IPHONE
</span><span class="cx"> @property (nonatomic, setter=_setWebGLEnabled:) BOOL _webGLEnabled WK_API_AVAILABLE(macos(10.13.4));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessAPICocoaWKUIDelegatePrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -152,6 +152,8 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_webView:(WKWebView *)webView willShareActivityItems:(NSArray *)activityItems WK_API_AVAILABLE(ios(WK_IOS_TBA));
</span><span class="cx"> 
</span><ins>+- (void)_webView:(WKWebView *)webView requestSpeechRecognitionPermissionForOrigin:(WKSecurityOrigin *)origin decisionHandler:(void (^)(BOOL authorized))decisionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
</ins><span class="cx"> #if TARGET_OS_IPHONE
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)_webView:(WKWebView *)webView shouldIncludeAppLinkActionsForElement:(_WKActivatedElementInfo *)element WK_API_AVAILABLE(ios(9.0));
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaMediaPermissionUtilitiesmm"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm                          (rev 0)
+++ trunk/Source/WebKit/UIProcess/Cocoa/MediaPermissionUtilities.mm     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,178 @@
</span><ins>+/*
+ * Copyright (C) 2020 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.
+ */
+
+#import "config.h"
+#import "MediaPermissionUtilities.h"
+
+#import "SandboxUtilities.h"
+#import "TCCSPI.h"
+#import <mutex>
+#import <wtf/BlockPtr.h>
+#import <wtf/SoftLinking.h>
+#import <wtf/spi/darwin/SandboxSPI.h>
+
+#if HAVE(SPEECHRECOGNIZER)
+#import <Speech/Speech.h>
+
+SOFT_LINK_FRAMEWORK(Speech)
+SOFT_LINK_CLASS(Speech, SFSpeechRecognizer)
+#endif
+
+#import <pal/cocoa/AVFoundationSoftLink.h>
+
+SOFT_LINK_PRIVATE_FRAMEWORK(TCC)
+SOFT_LINK(TCC, TCCAccessPreflight, TCCAccessPreflightResult, (CFStringRef service, CFDictionaryRef options), (service, options))
+SOFT_LINK_CONSTANT(TCC, kTCCServiceMicrophone, CFStringRef)
+SOFT_LINK_CONSTANT(TCC, kTCCServiceCamera, CFStringRef)
+
+namespace WebKit {
+
+bool checkSandboxRequirementForType(MediaPermissionType type)
+{
+#if PLATFORM(MAC)
+    static std::once_flag audioFlag;
+    static std::once_flag videoFlag;
+    static bool isAudioEntitled = true;
+    static bool isVideoEntitled = true;
+    
+    auto checkFunction = [](const char* operation, bool* entitled) {
+        if (!currentProcessIsSandboxed())
+            return;
+
+        int result = sandbox_check(getpid(), operation, SANDBOX_FILTER_NONE);
+        if (result == -1)
+            WTFLogAlways("Error checking '%s' sandbox access, errno=%ld", operation, (long)errno);
+        *entitled = !result;
+    };
+
+    switch (type) {
+    case MediaPermissionType::Audio:
+        std::call_once(audioFlag, checkFunction, "device-microphone", &isAudioEntitled);
+        return isAudioEntitled;
+    case MediaPermissionType::Video:
+        std::call_once(videoFlag, checkFunction, "device-camera", &isVideoEntitled);
+        return isVideoEntitled;
+    }
+#endif
+    return true;
+}
+
+bool checkUsageDescriptionStringForType(MediaPermissionType type)
+{
+    static std::once_flag audioDescriptionFlag;
+    static std::once_flag videoDescriptionFlag;
+    static bool hasMicrophoneDescriptionString = false;
+    static bool hasCameraDescriptionString = false;
+
+    switch (type) {
+    case MediaPermissionType::Audio:
+        static TCCAccessPreflightResult audioAccess = TCCAccessPreflight(getkTCCServiceMicrophone(), NULL);
+        if (audioAccess == kTCCAccessPreflightGranted)
+            return true;
+        std::call_once(audioDescriptionFlag, [] {
+            hasMicrophoneDescriptionString = dynamic_objc_cast<NSString>(NSBundle.mainBundle.infoDictionary[@"NSMicrophoneUsageDescription"]).length > 0;
+        });
+        return hasMicrophoneDescriptionString;
+    case MediaPermissionType::Video:
+        static TCCAccessPreflightResult videoAccess = TCCAccessPreflight(getkTCCServiceCamera(), NULL);
+        if (videoAccess == kTCCAccessPreflightGranted)
+            return true;
+        std::call_once(videoDescriptionFlag, [] {
+            hasCameraDescriptionString = dynamic_objc_cast<NSString>(NSBundle.mainBundle.infoDictionary[@"NSMicrophoneUsageDescription"]).length > 0;
+        });
+        return hasCameraDescriptionString;
+    }
+}
+
+bool checkUsageDescriptionStringForSpeechRecognition()
+{
+    return dynamic_objc_cast<NSString>(NSBundle.mainBundle.infoDictionary[@"NSSpeechRecognitionUsageDescription"]).length > 0;
+}
+
+#if HAVE(AVCAPTUREDEVICE)
+
+void requestAVCaptureAccessForType(MediaPermissionType type, CompletionHandler<void(bool authorized)>&& completionHandler)
+{
+    ASSERT(isMainThread());
+
+    AVMediaType mediaType = type == MediaPermissionType::Audio ? AVMediaTypeAudio : AVMediaTypeVideo;
+    auto decisionHandler = makeBlockPtr([completionHandler = WTFMove(completionHandler)](BOOL authorized) mutable {
+        if (isMainThread()) {
+            completionHandler(authorized);
+            return;
+        }
+
+        callOnMainThread([completionHandler = WTFMove(completionHandler), authorized]() mutable {
+            completionHandler(authorized);
+        });
+    });
+    [PAL::getAVCaptureDeviceClass() requestAccessForMediaType:mediaType completionHandler:decisionHandler.get()];
+}
+
+MediaPermissionResult checkAVCaptureAccessForType(MediaPermissionType type)
+{
+    AVMediaType mediaType = type == MediaPermissionType::Audio ? AVMediaTypeAudio : AVMediaTypeVideo;
+    auto authorizationStatus = [PAL::getAVCaptureDeviceClass() authorizationStatusForMediaType:mediaType];
+    if (authorizationStatus == AVAuthorizationStatusDenied || authorizationStatus == AVAuthorizationStatusRestricted)
+        return MediaPermissionResult::Denied;
+    if (authorizationStatus == AVAuthorizationStatusNotDetermined)
+        return MediaPermissionResult::Unknown;
+    return MediaPermissionResult::Granted;
+}
+
+#endif // HAVE(AVCAPTUREDEVICE)
+
+#if HAVE(SPEECHRECOGNIZER)
+
+void requestSpeechRecognitionAccess(CompletionHandler<void(bool authorized)>&& completionHandler)
+{
+    ASSERT(isMainThread());
+
+    auto decisionHandler = makeBlockPtr([completionHandler = WTFMove(completionHandler)](SFSpeechRecognizerAuthorizationStatus status) mutable {
+        bool authorized = status == SFSpeechRecognizerAuthorizationStatusAuthorized;
+        if (!isMainThread()) {
+            callOnMainThread([completionHandler = WTFMove(completionHandler), authorized]() mutable {
+                completionHandler(authorized);
+            });
+            return;
+        }
+        completionHandler(authorized);
+    });
+    [getSFSpeechRecognizerClass() requestAuthorization:decisionHandler.get()];
+}
+
+MediaPermissionResult checkSpeechRecognitionServiceAccess()
+{
+    auto authorizationStatus = [getSFSpeechRecognizerClass() authorizationStatus];
+    if (authorizationStatus == SFSpeechRecognizerAuthorizationStatusDenied || authorizationStatus == SFSpeechRecognizerAuthorizationStatusRestricted)
+        return MediaPermissionResult::Denied;
+    if (authorizationStatus == SFSpeechRecognizerAuthorizationStatusAuthorized)
+        return MediaPermissionResult::Granted;
+    return MediaPermissionResult::Unknown;
+}
+
+#endif // HAVE(SPEECHRECOGNIZER)
+
+} // namespace WebKit
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaUIDelegateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h 2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.h    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -161,6 +161,7 @@
</span><span class="cx"> #if ENABLE(WEB_AUTHN)
</span><span class="cx">         void runWebAuthenticationPanel(WebPageProxy&, API::WebAuthenticationPanel&, WebFrameProxy&, FrameInfoData&&, CompletionHandler<void(WebAuthenticationPanelResult)>&&) final;
</span><span class="cx"> #endif
</span><ins>+        void decidePolicyForSpeechRecognitionPermissionRequest(WebPageProxy&, API::SecurityOrigin&, CompletionHandler<void(bool)>&&) final;
</ins><span class="cx"> 
</span><span class="cx">         UIDelegate& m_uiDelegate;
</span><span class="cx">     };
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaUIDelegatemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1332,4 +1332,26 @@
</span><span class="cx">     [static_cast<id <WKUIDelegatePrivate>>(delegate) _webView:m_uiDelegate.m_webView imageOrMediaDocumentSizeChanged:newSize];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void UIDelegate::UIClient::decidePolicyForSpeechRecognitionPermissionRequest(WebKit::WebPageProxy& page, API::SecurityOrigin& origin, CompletionHandler<void(bool)>&& completionHandler)
+{
+    auto delegate = (id <WKUIDelegatePrivate>)m_uiDelegate.m_delegate.get();
+    if (!delegate) {
+        completionHandler(false);
+        return;
+    }
+
+    if (![delegate respondsToSelector:@selector(_webView:requestSpeechRecognitionPermissionForOrigin:decisionHandler:)]) {
+        completionHandler(false);
+        return;
+    }
+
+    auto checker = CompletionHandlerCallChecker::create(delegate, @selector(_webView:requestSpeechRecognitionPermissionForOrigin:decisionHandler:));
+    [delegate _webView:m_uiDelegate.m_webView requestSpeechRecognitionPermissionForOrigin:wrapper(origin) decisionHandler:makeBlockPtr([completionHandler = std::exchange(completionHandler, { }), checker = WTFMove(checker)] (BOOL granted) mutable {
+        if (checker->completionHandlerHasBeenCalled())
+            return;
+        checker->didCallCompletionHandler();
+        completionHandler(granted);
+    }).get()];
+}
+
</ins><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaUserMediaPermissionRequestManagerProxymm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UserMediaPermissionRequestManagerProxy.mm       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #import "config.h"
</span><span class="cx"> #import "UserMediaPermissionRequestManagerProxy.h"
</span><span class="cx"> 
</span><ins>+#import "MediaPermissionUtilities.h"
</ins><span class="cx"> #import "SandboxUtilities.h"
</span><span class="cx"> #import "TCCSPI.h"
</span><span class="cx"> #import "WebPageProxy.h"
</span><span class="lines">@@ -37,40 +38,12 @@
</span><span class="cx"> #import <pal/cocoa/AVFoundationSoftLink.h>
</span><span class="cx"> #import <wtf/spi/darwin/SandboxSPI.h>
</span><span class="cx"> 
</span><del>-SOFT_LINK_PRIVATE_FRAMEWORK(TCC)
-SOFT_LINK(TCC, TCCAccessPreflight, TCCAccessPreflightResult, (CFStringRef service, CFDictionaryRef options), (service, options))
-SOFT_LINK(TCC, TCCAccessPreflightWithAuditToken, TCCAccessPreflightResult, (CFStringRef service, audit_token_t token, CFDictionaryRef options), (service, token, options))
-SOFT_LINK_CONSTANT(TCC, kTCCServiceMicrophone, CFStringRef)
-SOFT_LINK_CONSTANT(TCC, kTCCServiceCamera, CFStringRef)
-
</del><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> bool UserMediaPermissionRequestManagerProxy::permittedToCaptureAudio()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-
-#if PLATFORM(MAC)
-    static std::once_flag onceFlag;
-    static bool entitled = true;
-    std::call_once(onceFlag, [] {
-        if (!currentProcessIsSandboxed())
-            return;
-
-        int result = sandbox_check(getpid(), "device-microphone", SANDBOX_FILTER_NONE);
-        entitled = !result;
-        if (result == -1)
-            WTFLogAlways("Error checking 'device-microphone' sandbox access, errno=%ld", (long)errno);
-    });
-    if (!entitled)
-        return false;
-#endif // PLATFORM(MAC)
-
-    static TCCAccessPreflightResult access = TCCAccessPreflight(getkTCCServiceMicrophone(), NULL);
-    if (access == kTCCAccessPreflightGranted)
-        return true;
-
-    static bool isPermitted = dynamic_objc_cast<NSString>(NSBundle.mainBundle.infoDictionary[@"NSMicrophoneUsageDescription"]).length;
-    return isPermitted;
</del><ins>+    return checkSandboxRequirementForType(MediaPermissionType::Audio) && checkUsageDescriptionStringForType(MediaPermissionType::Audio);
</ins><span class="cx"> #else
</span><span class="cx">     return false;
</span><span class="cx"> #endif
</span><span class="lines">@@ -79,29 +52,7 @@
</span><span class="cx"> bool UserMediaPermissionRequestManagerProxy::permittedToCaptureVideo()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-
-#if PLATFORM(MAC)
-    static std::once_flag onceFlag;
-    static bool entitled = true;
-    std::call_once(onceFlag, [] {
-        if (!currentProcessIsSandboxed())
-            return;
-
-        int result = sandbox_check(getpid(), "device-camera", SANDBOX_FILTER_NONE);
-        entitled = !result;
-        if (result == -1)
-            WTFLogAlways("Error checking 'device-camera' sandbox access, errno=%ld", (long)errno);
-    });
-    if (!entitled)
-        return false;
-#endif // PLATFORM(MAC)
-
-    static TCCAccessPreflightResult access = TCCAccessPreflight(getkTCCServiceCamera(), NULL);
-    if (access == kTCCAccessPreflightGranted)
-        return true;
-
-    static bool isPermitted = dynamic_objc_cast<NSString>(NSBundle.mainBundle.infoDictionary[@"NSCameraUsageDescription"]).length;
-    return isPermitted;
</del><ins>+    return checkSandboxRequirementForType(MediaPermissionType::Video) && checkUsageDescriptionStringForType(MediaPermissionType::Video);
</ins><span class="cx"> #else
</span><span class="cx">     return false;
</span><span class="cx"> #endif
</span><span class="lines">@@ -108,20 +59,6 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><del>-static void requestAVCaptureAccessForMediaType(CompletionHandler<void(BOOL authorized)>&& completionHandler, AVMediaType type)
-{
-    auto decisionHandler = makeBlockPtr([completionHandler = WTFMove(completionHandler)](BOOL authorized) mutable {
-        if (!isMainThread()) {
-            callOnMainThread([completionHandler = WTFMove(completionHandler), authorized]() mutable {
-                completionHandler(authorized);
-            });
-            return;
-        }
-        completionHandler(authorized);
-    });
-    [PAL::getAVCaptureDeviceClass() requestAccessForMediaType:type completionHandler:decisionHandler.get()];
-}
-
</del><span class="cx"> void UserMediaPermissionRequestManagerProxy::requestSystemValidation(const WebPageProxy& page, UserMediaPermissionRequestProxy& request, CompletionHandler<void(bool)>&& callback)
</span><span class="cx"> {
</span><span class="cx">     if (page.preferences().mockCaptureDevicesEnabled()) {
</span><span class="lines">@@ -130,36 +67,36 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // FIXME: Add TCC entitlement check for screensharing.
</span><del>-    bool requiresAudioCapture = request.requiresAudioCapture();
-    bool requiresVideoCapture = request.requiresVideoCapture();
-
-    auto microphoneAuthorizationStatus = !requiresAudioCapture ? AVAuthorizationStatusAuthorized : [PAL::getAVCaptureDeviceClass() authorizationStatusForMediaType:AVMediaTypeAudio];
-    if (microphoneAuthorizationStatus == AVAuthorizationStatusDenied || microphoneAuthorizationStatus == AVAuthorizationStatusRestricted) {
</del><ins>+    auto audioStatus = request.requiresAudioCapture() ? checkAVCaptureAccessForType(MediaPermissionType::Audio) : MediaPermissionResult::Granted;
+    if (audioStatus == MediaPermissionResult::Denied) {
</ins><span class="cx">         callback(false);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    auto cameraAuthorizationStatus = !requiresVideoCapture ? AVAuthorizationStatusAuthorized : [PAL::getAVCaptureDeviceClass() authorizationStatusForMediaType:AVMediaTypeVideo];
-    if (cameraAuthorizationStatus == AVAuthorizationStatusDenied || cameraAuthorizationStatus == AVAuthorizationStatusRestricted) {
</del><ins>+    auto videoStatus = request.requiresVideoCapture() ? checkAVCaptureAccessForType(MediaPermissionType::Video) : MediaPermissionResult::Granted;
+    if (videoStatus == MediaPermissionResult::Denied) {
</ins><span class="cx">         callback(false);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool requiresVideoTCCPrompt = requiresVideoCapture && cameraAuthorizationStatus == AVAuthorizationStatusNotDetermined;
-    auto completionHandler = requiresVideoTCCPrompt ? [request = makeRef(request), callback = WTFMove(callback)](bool isOK) mutable {
-        if (!isOK) {
-            callback(false);
-            return;
-        }
-        requestAVCaptureAccessForMediaType(WTFMove(callback), AVMediaTypeVideo);
-    } : WTFMove(callback);
</del><ins>+    if (audioStatus == MediaPermissionResult::Unknown) {
+        requestAVCaptureAccessForType(MediaPermissionType::Audio, [videoStatus, completionHandler = WTFMove(callback)](bool authorized) mutable {
+            if (videoStatus == MediaPermissionResult::Granted) {
+                completionHandler(authorized);
+                return;
+            }
+                
+            requestAVCaptureAccessForType(MediaPermissionType::Video, WTFMove(completionHandler));
+        });
+        return;
+    }
</ins><span class="cx"> 
</span><del>-    bool requiresAudioTCCPrompt = requiresAudioCapture && microphoneAuthorizationStatus == AVAuthorizationStatusNotDetermined;
-    if (!requiresAudioTCCPrompt) {
-        completionHandler(true);
</del><ins>+    if (videoStatus == MediaPermissionResult::Unknown) {
+        requestAVCaptureAccessForType(MediaPermissionType::Video, WTFMove(callback));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    requestAVCaptureAccessForMediaType(WTFMove(completionHandler), AVMediaTypeAudio);
</del><ins>+
+    callback(true);
</ins><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(MEDIA_STREAM)
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessCocoaWebProcessProxyCocoamm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm      2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebProcessProxyCocoa.mm 2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -41,6 +41,10 @@
</span><span class="cx"> #import <wtf/cocoa/VectorCocoa.h>
</span><span class="cx"> #import <wtf/spi/darwin/SandboxSPI.h>
</span><span class="cx"> 
</span><ins>+#if PLATFORM(IOS_FAMILY)
+#import "AccessibilitySupportSPI.h"
+#endif
+
</ins><span class="cx"> #if ENABLE(REMOTE_INSPECTOR)
</span><span class="cx"> #import <JavaScriptCore/RemoteInspectorConstants.h>
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessMediaPermissionUtilitieshfromrev269809trunkSourceWebCoreModulesspeechSpeechRecognitionRequesth"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h (from rev 269809, trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h) (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h                         (rev 0)
+++ trunk/Source/WebKit/UIProcess/MediaPermissionUtilities.h    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+/*
+ * Copyright (C) 2020 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
+
+#include <wtf/CompletionHandler.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+
+enum class MediaPermissionType {
+    Audio,
+    Video
+};
+
+enum class MediaPermissionResult {
+    Denied,
+    Granted,
+    Unknown
+};
+
+#if PLATFORM(COCOA)
+bool checkSandboxRequirementForType(MediaPermissionType);
+bool checkUsageDescriptionStringForType(MediaPermissionType);
+bool checkUsageDescriptionStringForSpeechRecognition();
+#endif
+
+#if HAVE(AVCAPTUREDEVICE)
+void requestAVCaptureAccessForType(MediaPermissionType, CompletionHandler<void(bool authorized)>&&);
+MediaPermissionResult checkAVCaptureAccessForType(MediaPermissionType);
+#endif
+
+#if HAVE(SPEECHRECOGNIZER)
+void requestSpeechRecognitionAccess(CompletionHandler<void(bool authorized)>&&);
+MediaPermissionResult checkSpeechRecognitionServiceAccess();
+#endif
+
+} // namespace WebKit
+
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionPermissionManagercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.cpp (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.cpp                             (rev 0)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.cpp        2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,223 @@
</span><ins>+/*
+ * Copyright (C) 2020 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 "config.h"
+#include "SpeechRecognitionPermissionManager.h"
+
+#include "APISecurityOrigin.h"
+#include "APIUIClient.h"
+#include "MediaPermissionUtilities.h"
+
+namespace WebKit {
+
+static SpeechRecognitionPermissionManager::CheckResult computeMicrophoneAccess()
+{
+#if HAVE(AVCAPTUREDEVICE)
+    auto result = checkAVCaptureAccessForType(MediaPermissionType::Audio);
+    if (result != MediaPermissionResult::Unknown)
+        return result == MediaPermissionResult::Granted ? SpeechRecognitionPermissionManager::CheckResult::Granted : SpeechRecognitionPermissionManager::CheckResult::Denied;
+    
+    if (!checkUsageDescriptionStringForType(MediaPermissionType::Audio))
+        return SpeechRecognitionPermissionManager::CheckResult::Denied;
+
+    return SpeechRecognitionPermissionManager::CheckResult::Unknown;
+#else
+    return SpeechRecognitionPermissionManager::CheckResult::Granted;
+#endif
+}
+
+static SpeechRecognitionPermissionManager::CheckResult computeSpeechRecognitionServiceAccess()
+{
+#if HAVE(SPEECHRECOGNIZER)
+    auto result = checkSpeechRecognitionServiceAccess();
+    if (result != MediaPermissionResult::Unknown)
+        return result == MediaPermissionResult::Granted ? SpeechRecognitionPermissionManager::CheckResult::Granted : SpeechRecognitionPermissionManager::CheckResult::Denied;
+
+    if (!checkUsageDescriptionStringForSpeechRecognition())
+        return SpeechRecognitionPermissionManager::CheckResult::Denied;
+
+    return SpeechRecognitionPermissionManager::CheckResult::Unknown;
+#else
+    return SpeechRecognitionPermissionManager::CheckResult::Granted;
+#endif
+}
+
+SpeechRecognitionPermissionManager::SpeechRecognitionPermissionManager(WebPageProxy& page)
+    : m_page(page)
+{
+}
+
+SpeechRecognitionPermissionManager::~SpeechRecognitionPermissionManager()
+{
+    for (auto& request : m_requests)
+        request->complete(SpeechRecognitionPermissionDecision::Deny);
+}
+    
+void SpeechRecognitionPermissionManager::request(const WebCore::ClientOrigin& origin, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&& completiontHandler)
+{
+    m_requests.append(SpeechRecognitionPermissionRequest::create(origin, WTFMove(completiontHandler)));
+    if (m_requests.size() == 1)
+        startNextRequest();
+}
+
+void SpeechRecognitionPermissionManager::startNextRequest()
+{
+    if (m_requests.isEmpty())
+        return;
+
+    startProcessingRequest();
+}
+
+void SpeechRecognitionPermissionManager::startProcessingRequest()
+{
+#if PLATFORM(COOCA)
+    if (!checkSandboxRequirementForType(MediaPermissionType::Audio)) {
+        completeCurrentRequest(SpeechRecognitionPermissionDecision::Deny);
+        return;
+    }
+#endif
+
+    // TCC status may have changed between requests.
+    m_microphoneCheck = computeMicrophoneAccess();
+    m_speechRecognitionServiceCheck = computeSpeechRecognitionServiceAccess();
+
+    if (m_page.preferences().mockCaptureDevicesEnabled()) {
+        m_microphoneCheck = CheckResult::Granted;
+        m_speechRecognitionServiceCheck = CheckResult::Granted;
+    }
+
+    // We currently don't allow third-party access.
+    if (m_userPermissionCheck == CheckResult::Unknown) {
+        auto clientOrigin = m_requests.first()->origin();
+        auto requestingOrigin = clientOrigin.clientOrigin.securityOrigin();
+        auto topOrigin = clientOrigin.topOrigin.securityOrigin();
+        if (!requestingOrigin->isSameOriginAs(topOrigin))
+            m_userPermissionCheck = CheckResult::Denied;
+    }
+
+    if (m_microphoneCheck == CheckResult::Denied || m_speechRecognitionServiceCheck == CheckResult::Denied || m_userPermissionCheck == CheckResult::Denied) {
+        completeCurrentRequest(SpeechRecognitionPermissionDecision::Deny);
+        return;
+    }
+
+    continueProcessingRequest();
+}
+
+void SpeechRecognitionPermissionManager::continueProcessingRequest()
+{
+    if (m_speechRecognitionServiceCheck == CheckResult::Unknown) {
+        requestSpeechRecognitionServiceAccess();
+        return;
+    }
+    ASSERT(m_speechRecognitionServiceCheck == CheckResult::Granted);
+
+    if (m_microphoneCheck == CheckResult::Unknown) {
+        requestMicrophoneAccess();
+        return;
+    }
+    ASSERT(m_microphoneCheck == CheckResult::Granted);
+
+    if (m_userPermissionCheck == CheckResult::Unknown) {
+        requestUserPermission();
+        return;
+    }
+    ASSERT(m_userPermissionCheck == CheckResult::Granted);
+
+    completeCurrentRequest(SpeechRecognitionPermissionDecision::Grant);
+}
+
+void SpeechRecognitionPermissionManager::completeCurrentRequest(SpeechRecognitionPermissionDecision decision)
+{
+    ASSERT(!m_requests.isEmpty());
+    auto currentRequest = m_requests.takeFirst();
+    currentRequest->complete(decision);
+
+    startNextRequest();
+}
+
+void SpeechRecognitionPermissionManager::requestSpeechRecognitionServiceAccess()
+{
+    ASSERT(m_speechRecognitionServiceCheck == CheckResult::Unknown);
+
+#if HAVE(SPEECHRECOGNIZER)
+    requestSpeechRecognitionAccess([this, weakThis = makeWeakPtr(this)](bool authorized) mutable {
+        if (!weakThis)
+            return;
+
+        m_speechRecognitionServiceCheck = authorized ? CheckResult::Granted : CheckResult::Denied;
+        if (m_speechRecognitionServiceCheck == CheckResult::Denied) {
+            completeCurrentRequest(SpeechRecognitionPermissionDecision::Deny);
+            return;
+        }
+
+        continueProcessingRequest();
+    });
+#endif
+}
+
+void SpeechRecognitionPermissionManager::requestMicrophoneAccess()
+{
+    ASSERT(m_microphoneCheck == CheckResult::Unknown);
+
+#if HAVE(AVCAPTUREDEVICE)
+    requestAVCaptureAccessForType(MediaPermissionType::Audio, [this, weakThis = makeWeakPtr(this)](bool authorized) {
+        if (!weakThis)
+            return;
+
+        m_microphoneCheck = authorized ? CheckResult::Granted : CheckResult::Denied;
+        if (m_microphoneCheck == CheckResult::Denied) {
+            completeCurrentRequest(SpeechRecognitionPermissionDecision::Deny);
+            return;
+        }
+
+        continueProcessingRequest();
+    });
+#endif
+}
+
+void SpeechRecognitionPermissionManager::requestUserPermission()
+{
+    ASSERT(!m_requests.isEmpty());
+
+    auto& currentRequest = m_requests.first();
+    auto clientOrigin = currentRequest->origin();
+    auto topOrigin = clientOrigin.topOrigin.securityOrigin();
+    auto decisionHandler = [this, weakThis = makeWeakPtr(*this)](bool granted) {
+        if (!weakThis)
+            return;
+
+        m_userPermissionCheck = granted ? CheckResult::Granted : CheckResult::Denied;
+        if (m_userPermissionCheck == CheckResult::Denied) {
+            completeCurrentRequest(SpeechRecognitionPermissionDecision::Deny);
+            return;
+        }
+
+        continueProcessingRequest();
+    };
+    m_page.uiClient().decidePolicyForSpeechRecognitionPermissionRequest(m_page, API::SecurityOrigin::create(topOrigin.get()).get(), WTFMove(decisionHandler));
+}
+
+} // namespace WebKit
+
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionPermissionManagerhfromrev269809trunkSourceWebCoreModulesspeechSpeechRecognitionRequesth"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.h (from rev 269809, trunk/Source/WebCore/Modules/speech/SpeechRecognitionRequest.h) (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.h                               (rev 0)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionManager.h  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+/*
+ * Copyright (C) 2020 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
+
+#include "SpeechRecognitionPermissionRequest.h"
+#include <wtf/Deque.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class SpeechRecognitionPermissionManager : public CanMakeWeakPtr<SpeechRecognitionPermissionManager> {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    enum class CheckResult { Denied, Granted, Unknown };
+    explicit SpeechRecognitionPermissionManager(WebPageProxy&);
+    ~SpeechRecognitionPermissionManager();
+    void request(const WebCore::ClientOrigin&, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&&);
+
+private:
+    void startNextRequest();
+    void startProcessingRequest();
+    void continueProcessingRequest();
+    void completeCurrentRequest(SpeechRecognitionPermissionDecision);
+    void requestMicrophoneAccess();
+    void requestSpeechRecognitionServiceAccess();
+    void requestUserPermission();
+
+    WebPageProxy& m_page;
+    Deque<Ref<SpeechRecognitionPermissionRequest>> m_requests;
+    CheckResult m_microphoneCheck { CheckResult::Unknown };
+    CheckResult m_speechRecognitionServiceCheck { CheckResult::Unknown };
+    CheckResult m_userPermissionCheck { CheckResult::Unknown };
+};
+
+} // namespace WebKit
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionPermissionRequesth"></a>
<div class="addfile"><h4>Added: trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionRequest.h (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionRequest.h                               (rev 0)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionPermissionRequest.h  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+/*
+ * Copyright (C) 2020 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
+
+#include "APIObject.h"
+#include <WebCore/ClientOrigin.h>
+#include <wtf/CompletionHandler.h>
+
+namespace WebKit {
+
+enum class SpeechRecognitionPermissionDecision : bool { Deny, Grant };
+
+class SpeechRecognitionPermissionRequest : public RefCounted<SpeechRecognitionPermissionRequest> {
+public:
+    static Ref<SpeechRecognitionPermissionRequest> create(const WebCore::ClientOrigin& origin, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&& completionHandler)
+    {
+        return adoptRef(*new SpeechRecognitionPermissionRequest(origin, WTFMove(completionHandler)));
+    }
+
+    void complete(SpeechRecognitionPermissionDecision decision)
+    {
+        auto completionHandler = std::exchange(m_completionHandler, { });
+        completionHandler(decision);
+    }
+
+    const WebCore::ClientOrigin& origin() const { return m_origin; }
+
+private:
+    SpeechRecognitionPermissionRequest(const WebCore::ClientOrigin& origin, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&& completionHandler)
+        : m_origin(origin)
+        , m_completionHandler(WTFMove(completionHandler))
+    { }
+
+    WebCore::ClientOrigin m_origin;
+    CompletionHandler<void(SpeechRecognitionPermissionDecision)> m_completionHandler;
+};
+
+class SpeechRecognitionPermissionCallback : public API::ObjectImpl<API::Object::Type::SpeechRecognitionPermissionCallback> {
+public:
+    static Ref<SpeechRecognitionPermissionCallback> create(CompletionHandler<void(bool)>&& completionHandler)
+    {
+        return adoptRef(*new SpeechRecognitionPermissionCallback(WTFMove(completionHandler)));
+    }
+
+    void complete(bool granted) { m_completionHandler(granted); }
+
+private:
+    SpeechRecognitionPermissionCallback(CompletionHandler<void(bool)>&& completionHandler)
+        : m_completionHandler(WTFMove(completionHandler))
+    { }
+
+    CompletionHandler<void(bool)> m_completionHandler;
+};
+
+} // namespace WebKit
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionServercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.cpp        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.cpp   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -30,89 +30,110 @@
</span><span class="cx"> #include "WebSpeechRecognitionConnectionMessages.h"
</span><span class="cx"> #include <WebCore/SpeechRecognitionUpdate.h>
</span><span class="cx"> 
</span><ins>+#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, messageSenderConnection())
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><del>-SpeechRecognitionServer::SpeechRecognitionServer(Ref<IPC::Connection>&& connection, SpeechRecognitionServerIdentifier identifier)
</del><ins>+SpeechRecognitionServer::SpeechRecognitionServer(Ref<IPC::Connection>&& connection, SpeechRecognitionServerIdentifier identifier, SpeechRecognitionPermissionChecker&& permissionChecker)
</ins><span class="cx">     : m_connection(WTFMove(connection))
</span><span class="cx">     , m_identifier(identifier)
</span><ins>+    , m_permissionChecker(WTFMove(permissionChecker))
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::start(WebCore::SpeechRecognitionRequestInfo&& requestInfo)
</del><ins>+void SpeechRecognitionServer::start(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier, String&& lang, bool continuous, bool interimResults, uint64_t maxAlternatives, WebCore::ClientOrigin&& origin)
</ins><span class="cx"> {
</span><del>-    auto request = WebCore::SpeechRecognitionRequest::create(WTFMove(requestInfo));
-    m_pendingRequests.append(WTFMove(request));
</del><ins>+    MESSAGE_CHECK(clientIdentifier);
+    ASSERT(!m_pendingRequests.contains(clientIdentifier));
+    ASSERT(!m_ongoingRequests.contains(clientIdentifier));
+    auto requestInfo = SpeechRecognitionRequestInfo { clientIdentifier, WTFMove(lang), continuous, interimResults, maxAlternatives, WTFMove(origin) };
+    auto& pendingRequest = m_pendingRequests.add(clientIdentifier, makeUnique<WebCore::SpeechRecognitionRequest>(WTFMove(requestInfo))).iterator->value;
</ins><span class="cx"> 
</span><del>-    processNextPendingRequestIfNeeded();
</del><ins>+    requestPermissionForRequest(*pendingRequest);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::processNextPendingRequestIfNeeded()
</del><ins>+void SpeechRecognitionServer::requestPermissionForRequest(WebCore::SpeechRecognitionRequest& request)
</ins><span class="cx"> {
</span><del>-    if (m_currentRequest)
-        return;
</del><ins>+    m_permissionChecker(request.clientOrigin(), [this, weakThis = makeWeakPtr(this), weakRequest = makeWeakPtr(request)](SpeechRecognitionPermissionDecision decision) mutable {
+        if (!weakThis)
+            return;
</ins><span class="cx"> 
</span><del>-    if (m_pendingRequests.isEmpty())
-        return;
</del><ins>+        if (!weakRequest)
+            return;
</ins><span class="cx"> 
</span><del>-    m_currentRequest = m_pendingRequests.takeFirst();
-    startPocessingRequest(*m_currentRequest);
</del><ins>+        auto identifier = weakRequest->clientIdentifier();
+        auto takenRequest = m_pendingRequests.take(identifier);
+        if (decision == SpeechRecognitionPermissionDecision::Deny) {
+            auto error = SpeechRecognitionError { SpeechRecognitionErrorType::NotAllowed, "Permission check failed"_s };
+            sendUpdate(identifier, WebCore::SpeechRecognitionUpdateType::Error, error);
+            return;
+        }
+
+        m_ongoingRequests.add(identifier, WTFMove(takenRequest));
+        handleRequest(*m_ongoingRequests.get(identifier));
+    });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeechRecognitionServer::stop(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</span><span class="cx"> {
</span><del>-    if (m_currentRequest && m_currentRequest->clientIdentifier() == clientIdentifier) {
-        stopProcessingRequest(*m_currentRequest);
</del><ins>+    MESSAGE_CHECK(clientIdentifier);
+    if (m_pendingRequests.remove(clientIdentifier)) {
+        sendUpdate(clientIdentifier, WebCore::SpeechRecognitionUpdateType::End);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    removePendingRequest(clientIdentifier);
</del><ins>+    ASSERT(m_ongoingRequests.contains(clientIdentifier));
+    stopRequest(*m_ongoingRequests.get(clientIdentifier));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeechRecognitionServer::abort(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</span><span class="cx"> {
</span><del>-    if (m_currentRequest && m_currentRequest->clientIdentifier() == clientIdentifier) {
-        m_currentRequest = nullptr;
-        auto update = WebCore::SpeechRecognitionUpdate::create(clientIdentifier, WebCore::SpeechRecognitionUpdateType::End);
-        send(Messages::WebSpeechRecognitionConnection::DidReceiveUpdate(update), m_identifier);
-
-        processNextPendingRequestIfNeeded();
</del><ins>+    MESSAGE_CHECK(clientIdentifier);
+    if (m_pendingRequests.remove(clientIdentifier)) {
+        sendUpdate(clientIdentifier, WebCore::SpeechRecognitionUpdateType::End);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    removePendingRequest(clientIdentifier);
</del><ins>+    ASSERT(m_ongoingRequests.contains(clientIdentifier));
+    auto request = m_ongoingRequests.take(clientIdentifier);
+    abortRequest(*request);
+    auto update = WebCore::SpeechRecognitionUpdate::create(clientIdentifier, WebCore::SpeechRecognitionUpdateType::End);
+    send(Messages::WebSpeechRecognitionConnection::DidReceiveUpdate(update), m_identifier);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::removePendingRequest(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</del><ins>+void SpeechRecognitionServer::invalidate(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</ins><span class="cx"> {
</span><del>-    RefPtr<WebCore::SpeechRecognitionRequest> takenRequest;
-    auto pendingRequests = std::exchange(m_pendingRequests, { });
-    while (!pendingRequests.isEmpty()) {
-        auto request = pendingRequests.takeFirst();
-        if (request->clientIdentifier() == clientIdentifier) {
-            auto update = WebCore::SpeechRecognitionUpdate::create(clientIdentifier, WebCore::SpeechRecognitionUpdateType::End);
-            send(Messages::WebSpeechRecognitionConnection::DidReceiveUpdate(update), m_identifier);
-            continue;
-        }
-        m_pendingRequests.append(WTFMove(request));
-    }
</del><ins>+    MESSAGE_CHECK(clientIdentifier);
+    auto request = m_ongoingRequests.take(clientIdentifier);
+    if (request)
+        abortRequest(*request);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::invalidate(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</del><ins>+void SpeechRecognitionServer::handleRequest(WebCore::SpeechRecognitionRequest& request)
</ins><span class="cx"> {
</span><del>-    if (m_currentRequest && m_currentRequest->clientIdentifier() == clientIdentifier) {
-        m_currentRequest = nullptr;
-        processNextPendingRequestIfNeeded();
-    }
</del><ins>+    // TODO: start capturing audio and recognition.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::startPocessingRequest(WebCore::SpeechRecognitionRequest&)
</del><ins>+void SpeechRecognitionServer::stopRequest(WebCore::SpeechRecognitionRequest& request)
</ins><span class="cx"> {
</span><ins>+    // TODO: stop capturing audio and finalizing results by recognizing captured audio.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SpeechRecognitionServer::stopProcessingRequest(WebCore::SpeechRecognitionRequest&)
</del><ins>+void SpeechRecognitionServer::abortRequest(WebCore::SpeechRecognitionRequest& request)
</ins><span class="cx"> {
</span><ins>+    // TODO: stop capturing audio and recognition immediately without generating results.
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SpeechRecognitionServer::sendUpdate(SpeechRecognitionConnectionClientIdentifier clientIdentifier, SpeechRecognitionUpdateType type, Optional<SpeechRecognitionError> error, Optional<Vector<SpeechRecognitionResultData>> result)
+{
+    auto update = WebCore::SpeechRecognitionUpdate::create(clientIdentifier, type);
+    if (type == SpeechRecognitionUpdateType::Error)
+        update = WebCore::SpeechRecognitionUpdate::createError(clientIdentifier, *error);
+    if (type == SpeechRecognitionUpdateType::Result)
+        update = WebCore::SpeechRecognitionUpdate::createResult(clientIdentifier, *result);
+    send(Messages::WebSpeechRecognitionConnection::DidReceiveUpdate(update), m_identifier);
+}
+
</ins><span class="cx"> IPC::Connection* SpeechRecognitionServer::messageSenderConnection() const
</span><span class="cx"> {
</span><span class="cx">     return m_connection.ptr();
</span><span class="lines">@@ -124,3 +145,5 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span><ins>+
+#undef MESSAGE_CHECK
</ins></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionServerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.h  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.h     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -28,33 +28,41 @@
</span><span class="cx"> #include "MessageReceiver.h"
</span><span class="cx"> #include "MessageSender.h"
</span><span class="cx"> #include <WebCore/PageIdentifier.h>
</span><ins>+#include <WebCore/SpeechRecognitionError.h>
</ins><span class="cx"> #include <WebCore/SpeechRecognitionRequest.h>
</span><ins>+#include <WebCore/SpeechRecognitionResultData.h>
</ins><span class="cx"> #include <wtf/Deque.h>
</span><span class="cx"> 
</span><ins>+namespace WebCore {
+enum class SpeechRecognitionUpdateType;
+struct ClientOrigin;
+}
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> class WebProcessProxy;
</span><ins>+enum class SpeechRecognitionPermissionDecision : bool;
</ins><span class="cx"> 
</span><span class="cx"> using SpeechRecognitionServerIdentifier = WebCore::PageIdentifier;
</span><ins>+using SpeechRecognitionPermissionChecker = Function<void(const WebCore::ClientOrigin&, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&&)>;
</ins><span class="cx"> 
</span><span class="cx"> class SpeechRecognitionServer : public CanMakeWeakPtr<SpeechRecognitionServer>, public IPC::MessageReceiver, private IPC::MessageSender {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><del>-    SpeechRecognitionServer(Ref<IPC::Connection>&&, SpeechRecognitionServerIdentifier);
</del><ins>+    SpeechRecognitionServer(Ref<IPC::Connection>&&, SpeechRecognitionServerIdentifier, SpeechRecognitionPermissionChecker&&);
</ins><span class="cx"> 
</span><del>-    void start(WebCore::SpeechRecognitionRequestInfo&&);
</del><ins>+    void start(WebCore::SpeechRecognitionConnectionClientIdentifier, String&& lang, bool continuous, bool interimResults, uint64_t maxAlternatives, WebCore::ClientOrigin&&);
</ins><span class="cx">     void stop(WebCore::SpeechRecognitionConnectionClientIdentifier);
</span><span class="cx">     void abort(WebCore::SpeechRecognitionConnectionClientIdentifier);
</span><span class="cx">     void invalidate(WebCore::SpeechRecognitionConnectionClientIdentifier);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void processNextPendingRequestIfNeeded();
-    void removePendingRequest(WebCore::SpeechRecognitionConnectionClientIdentifier);
</del><ins>+    void requestPermissionForRequest(WebCore::SpeechRecognitionRequest&);
+    void handleRequest(WebCore::SpeechRecognitionRequest&);
+    void stopRequest(WebCore::SpeechRecognitionRequest&);
+    void abortRequest(WebCore::SpeechRecognitionRequest&);
+    void sendUpdate(WebCore::SpeechRecognitionConnectionClientIdentifier, WebCore::SpeechRecognitionUpdateType, Optional<WebCore::SpeechRecognitionError> = WTF::nullopt, Optional<Vector<WebCore::SpeechRecognitionResultData>> = WTF::nullopt);
</ins><span class="cx"> 
</span><del>-    // TODO: implement these.
-    void startPocessingRequest(WebCore::SpeechRecognitionRequest&);
-    void stopProcessingRequest(WebCore::SpeechRecognitionRequest&);
-
</del><span class="cx">     // IPC::MessageReceiver.
</span><span class="cx">     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
</span><span class="cx"> 
</span><span class="lines">@@ -64,8 +72,9 @@
</span><span class="cx"> 
</span><span class="cx">     Ref<IPC::Connection> m_connection;
</span><span class="cx">     SpeechRecognitionServerIdentifier m_identifier;
</span><del>-    Deque<Ref<WebCore::SpeechRecognitionRequest>> m_pendingRequests;
-    RefPtr<WebCore::SpeechRecognitionRequest> m_currentRequest;
</del><ins>+    HashMap<WebCore::SpeechRecognitionConnectionClientIdentifier, std::unique_ptr<WebCore::SpeechRecognitionRequest>> m_pendingRequests;
+    HashMap<WebCore::SpeechRecognitionConnectionClientIdentifier, std::unique_ptr<WebCore::SpeechRecognitionRequest>> m_ongoingRequests;
+    SpeechRecognitionPermissionChecker m_permissionChecker;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessSpeechRecognitionServermessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.messages.in (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.messages.in        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/SpeechRecognitionServer.messages.in   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx">  */
</span><span class="cx">  
</span><span class="cx">  messages -> SpeechRecognitionServer NotRefCounted {
</span><del>-    Start(struct WebCore::SpeechRecognitionRequestInfo info)
</del><ins>+    Start(WebCore::SpeechRecognitionConnectionClientIdentifier identifier, String lang, bool continuous, bool interimResults, uint64_t maxAlternatives, struct WebCore::ClientOrigin origin)
</ins><span class="cx">     Stop(WebCore::SpeechRecognitionConnectionClientIdentifier identifier)
</span><span class="cx">     Abort(WebCore::SpeechRecognitionConnectionClientIdentifier identifier)
</span><span class="cx">     Invalidate(WebCore::SpeechRecognitionConnectionClientIdentifier identifier)
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -86,6 +86,7 @@
</span><span class="cx"> #include "ProvisionalPageProxy.h"
</span><span class="cx"> #include "SafeBrowsingWarning.h"
</span><span class="cx"> #include "SharedBufferDataReference.h"
</span><ins>+#include "SpeechRecognitionPermissionManager.h"
</ins><span class="cx"> #include "SyntheticEditingCommandType.h"
</span><span class="cx"> #include "TextChecker.h"
</span><span class="cx"> #include "TextCheckerState.h"
</span><span class="lines">@@ -4893,6 +4894,8 @@
</span><span class="cx">     UNUSED_PARAM(frameID);
</span><span class="cx"> #endif
</span><span class="cx">     m_isQuotaIncreaseDenied = false;
</span><ins>+
+    m_speechRecognitionPermissionManager = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::viewIsBecomingVisible()
</span><span class="lines">@@ -7606,6 +7609,8 @@
</span><span class="cx"> #if ENABLE(WEB_AUTHN)
</span><span class="cx">     m_websiteDataStore->authenticatorManager().cancelRequest(m_webPageID, WTF::nullopt);
</span><span class="cx"> #endif
</span><ins>+
+    m_speechRecognitionPermissionManager = nullptr;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason terminationReason)
</span><span class="lines">@@ -10235,6 +10240,14 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPageProxy::requestSpeechRecognitionPermission(const WebCore::ClientOrigin& clientOrigin, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&& completionHandler)
+{
+    if (!m_speechRecognitionPermissionManager)
+        m_speechRecognitionPermissionManager = makeUnique<SpeechRecognitionPermissionManager>(*this);
+
+    m_speechRecognitionPermissionManager->request(clientOrigin, WTFMove(completionHandler));
+}
+
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #undef RELEASE_LOG_IF_ALLOWED
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebPageProxy.h     2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h        2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -304,6 +304,7 @@
</span><span class="cx"> class RemoteLayerTreeTransaction;
</span><span class="cx"> class RemoteScrollingCoordinatorProxy;
</span><span class="cx"> class SecKeyProxyStore;
</span><ins>+class SpeechRecognitionPermissionManager;
</ins><span class="cx"> class UserData;
</span><span class="cx"> class ViewSnapshot;
</span><span class="cx"> class VisitedLinkStore;
</span><span class="lines">@@ -364,6 +365,7 @@
</span><span class="cx"> 
</span><span class="cx"> enum class NegotiatedLegacyTLS : bool;
</span><span class="cx"> enum class ProcessSwapRequestedByClient : bool;
</span><ins>+enum class SpeechRecognitionPermissionDecision : bool;
</ins><span class="cx"> enum class UndoOrRedo : bool;
</span><span class="cx"> enum class WebContentMode : uint8_t;
</span><span class="cx"> 
</span><span class="lines">@@ -1818,6 +1820,8 @@
</span><span class="cx">     void setMediaCaptureReportingDelay(Seconds captureReportingDelay) { m_mediaCaptureReportingDelay = captureReportingDelay; }
</span><span class="cx">     size_t suspendMediaPlaybackCounter() { return m_suspendMediaPlaybackCounter; }
</span><span class="cx"> 
</span><ins>+    void requestSpeechRecognitionPermission(const WebCore::ClientOrigin&, CompletionHandler<void(SpeechRecognitionPermissionDecision)>&&);
+
</ins><span class="cx"> private:
</span><span class="cx">     WebPageProxy(PageClient&, WebProcessProxy&, Ref<API::PageConfiguration>&&);
</span><span class="cx">     void platformInitialize();
</span><span class="lines">@@ -2839,6 +2843,9 @@
</span><span class="cx">     };
</span><span class="cx">     Optional<SpeechSynthesisData> m_speechSynthesisData;
</span><span class="cx"> #endif
</span><ins>+
+    std::unique_ptr<SpeechRecognitionPermissionManager> m_speechRecognitionPermissionManager;
+
</ins><span class="cx"> #if USE(DIRECT2D)
</span><span class="cx">     COMPtr<ID3D11Device1> m_device;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessWebProcessProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include "PluginInfoStore.h"
</span><span class="cx"> #include "PluginProcessManager.h"
</span><span class="cx"> #include "ProvisionalPageProxy.h"
</span><ins>+#include "SpeechRecognitionPermissionRequest.h"
</ins><span class="cx"> #include "SpeechRecognitionServerMessages.h"
</span><span class="cx"> #include "TextChecker.h"
</span><span class="cx"> #include "TextCheckerState.h"
</span><span class="lines">@@ -1703,7 +1704,25 @@
</span><span class="cx"> {
</span><span class="cx">     auto speechRecognitionServer = m_speechRecognitionServerMap.add(identifier, nullptr);
</span><span class="cx">     ASSERT(speechRecognitionServer.isNewEntry);
</span><del>-    speechRecognitionServer.iterator->value = makeUnique<SpeechRecognitionServer>(makeRef(*connection()), identifier);
</del><ins>+    WebPageProxy* targetPage = nullptr;
+    for (auto* page : pages()) {
+        if (page && page->webPageID() == identifier) {
+            targetPage = page;
+            break;
+        }
+    }
+
+    if (!targetPage)
+        return;
+
+    speechRecognitionServer.iterator->value = makeUnique<SpeechRecognitionServer>(makeRef(*connection()), identifier, [weakPage = makeWeakPtr(targetPage)](auto& origin, auto&& completionHandler) mutable {
+        if (!weakPage) {
+            completionHandler(SpeechRecognitionPermissionDecision::Deny);
+            return;
+        }
+
+        weakPage->requestSpeechRecognitionPermission(origin, WTFMove(completionHandler));
+    });
</ins><span class="cx">     addMessageReceiver(Messages::SpeechRecognitionServer::messageReceiverName(), identifier, *speechRecognitionServer.iterator->value);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitWebKitxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj     2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj        2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1369,6 +1369,7 @@
</span><span class="cx">          933E835523A07C0600DEF289 /* WebIDBServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 933E835323A07BF800DEF289 /* WebIDBServer.h */; };
</span><span class="cx">          933E835A23A1AE2800DEF289 /* WebIDBServerMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 933E835923A1ADF500DEF289 /* WebIDBServerMessages.h */; };
</span><span class="cx">          933E835B23A1B75000DEF289 /* WebIDBServerMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 933E835823A1ADF500DEF289 /* WebIDBServerMessageReceiver.cpp */; };
</span><ins>+               9342589A255B535A0059EEDD /* MediaPermissionUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 93425898255B534B0059EEDD /* MediaPermissionUtilities.h */; };
</ins><span class="cx">           934B724419F5B9BE00AE96D6 /* WKActionMenuItemTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 934B724319F5B9BE00AE96D6 /* WKActionMenuItemTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          9356F2DC2152B6B500E6D5DF /* WebSWClientConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 517A53021F4793B200DCDC0A /* WebSWClientConnection.h */; };
</span><span class="cx">          9356F2DD2152B6F600E6D5DF /* WebSWServerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 93BA04E02151ADF4007F455F /* WebSWServerConnection.h */; };
</span><span class="lines">@@ -1403,6 +1404,9 @@
</span><span class="cx">          93D6B787254CCD8C0058DD3A /* WebSpeechRecognitionConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B786254CCD8B0058DD3A /* WebSpeechRecognitionConnectionMessages.h */; };
</span><span class="cx">          93D6B788254CCD940058DD3A /* WebSpeechRecognitionConnectionMessagesReplies.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B77E254CCABB0058DD3A /* WebSpeechRecognitionConnectionMessagesReplies.h */; };
</span><span class="cx">          93D6B78A254CD43E0058DD3A /* WebSpeechRecognitionConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93D6B77D254CCABB0058DD3A /* WebSpeechRecognitionConnectionMessageReceiver.cpp */; };
</span><ins>+               93D6B7B4255268D50058DD3A /* SpeechRecognitionPermissionRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7AF255268A10058DD3A /* SpeechRecognitionPermissionRequest.h */; };
+               93D6B7B5255268D70058DD3A /* SpeechRecognitionPermissionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7B2255268A20058DD3A /* SpeechRecognitionPermissionManager.h */; };
+               93D6B7B925534A170058DD3A /* WKSpeechRecognitionPermissionCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           93E6A4EE1BC5DD3900F8A0E7 /* _WKHitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          93F549B41E3174B7000E7239 /* WKSnapshotConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
</span><span class="cx">          950F2880252414EA00B74F1C /* WKMouseDeviceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 950F287E252414E900B74F1C /* WKMouseDeviceObserver.h */; };
</span><span class="lines">@@ -4450,6 +4454,8 @@
</span><span class="cx">          933E835723A1A87200DEF289 /* WebIDBServer.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebIDBServer.messages.in; sourceTree = "<group>"; };
</span><span class="cx">          933E835823A1ADF500DEF289 /* WebIDBServerMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebIDBServerMessageReceiver.cpp; path = DerivedSources/WebKit2/WebIDBServerMessageReceiver.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
</span><span class="cx">          933E835923A1ADF500DEF289 /* WebIDBServerMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebIDBServerMessages.h; path = DerivedSources/WebKit2/WebIDBServerMessages.h; sourceTree = BUILT_PRODUCTS_DIR; };
</span><ins>+               9342588F2555DCA50059EEDD /* MediaPermissionUtilities.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaPermissionUtilities.mm; sourceTree = "<group>"; };
+               93425898255B534B0059EEDD /* MediaPermissionUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPermissionUtilities.h; sourceTree = "<group>"; };
</ins><span class="cx">           934B724319F5B9BE00AE96D6 /* WKActionMenuItemTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKActionMenuItemTypes.h; sourceTree = "<group>"; };
</span><span class="cx">          935EEB951277616D003322B8 /* WKBundleBackForwardList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKBundleBackForwardList.cpp; sourceTree = "<group>"; };
</span><span class="cx">          935EEB961277616D003322B8 /* WKBundleBackForwardList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBundleBackForwardList.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -4510,6 +4516,11 @@
</span><span class="cx">          93D6B780254CCABC0058DD3A /* SpeechRecognitionServerMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeechRecognitionServerMessages.h; sourceTree = "<group>"; };
</span><span class="cx">          93D6B781254CCABC0058DD3A /* SpeechRecognitionServerMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeechRecognitionServerMessageReceiver.cpp; sourceTree = "<group>"; };
</span><span class="cx">          93D6B786254CCD8B0058DD3A /* WebSpeechRecognitionConnectionMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSpeechRecognitionConnectionMessages.h; sourceTree = "<group>"; };
</span><ins>+               93D6B7AF255268A10058DD3A /* SpeechRecognitionPermissionRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeechRecognitionPermissionRequest.h; sourceTree = "<group>"; };
+               93D6B7B0255268A10058DD3A /* SpeechRecognitionPermissionManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpeechRecognitionPermissionManager.cpp; sourceTree = "<group>"; };
+               93D6B7B2255268A20058DD3A /* SpeechRecognitionPermissionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpeechRecognitionPermissionManager.h; sourceTree = "<group>"; };
+               93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKSpeechRecognitionPermissionCallback.h; sourceTree = "<group>"; };
+               93D6B7B825534A120058DD3A /* WKSpeechRecognitionPermissionCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKSpeechRecognitionPermissionCallback.cpp; sourceTree = "<group>"; };
</ins><span class="cx">           93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKHitTestResult.h; sourceTree = "<group>"; };
</span><span class="cx">          93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKSnapshotConfiguration.h; sourceTree = "<group>"; };
</span><span class="cx">          93F549B51E3174DA000E7239 /* WKSnapshotConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKSnapshotConfiguration.mm; sourceTree = "<group>"; };
</span><span class="lines">@@ -6448,6 +6459,7 @@
</span><span class="cx">                          7A821F4D1E2F679E00604577 /* LegacyCustomProtocolManagerClient.mm */,
</span><span class="cx">                          A1DF631118E0B7C8003A3E2A /* LegacyDownloadClient.h */,
</span><span class="cx">                          A1DF631018E0B7C8003A3E2A /* LegacyDownloadClient.mm */,
</span><ins>+                               9342588F2555DCA50059EEDD /* MediaPermissionUtilities.mm */,
</ins><span class="cx">                           411286EF21C8A90C003A8550 /* MediaUtilities.h */,
</span><span class="cx">                          411286F021C8A90D003A8550 /* MediaUtilities.mm */,
</span><span class="cx">                          1ABC3DF41899E437004F0626 /* NavigationState.h */,
</span><span class="lines">@@ -9187,6 +9199,7 @@
</span><span class="cx">                          5CEABA2B2333251400797797 /* LegacyGlobalSettings.cpp */,
</span><span class="cx">                          5CEABA2A2333247700797797 /* LegacyGlobalSettings.h */,
</span><span class="cx">                          31607F3819627002009B87DA /* LegacySessionStateCoding.h */,
</span><ins>+                               93425898255B534B0059EEDD /* MediaPermissionUtilities.h */,
</ins><span class="cx">                           BC6EDAA5111271C600E7678B /* PageClient.h */,
</span><span class="cx">                          1AC75379183A9FDA0072CB15 /* PageLoadState.cpp */,
</span><span class="cx">                          1AC7537A183A9FDB0072CB15 /* PageLoadState.h */,
</span><span class="lines">@@ -9206,6 +9219,9 @@
</span><span class="cx">                          BC111B08112F5E3C00337BAB /* ResponsivenessTimer.cpp */,
</span><span class="cx">                          1A30066C1110F4F70031937C /* ResponsivenessTimer.h */,
</span><span class="cx">                          5CA98549210BEB5A0057EB6B /* SafeBrowsingWarning.h */,
</span><ins>+                               93D6B7B0255268A10058DD3A /* SpeechRecognitionPermissionManager.cpp */,
+                               93D6B7B2255268A20058DD3A /* SpeechRecognitionPermissionManager.h */,
+                               93D6B7AF255268A10058DD3A /* SpeechRecognitionPermissionRequest.h */,
</ins><span class="cx">                           93D6B76B254B89580058DD3A /* SpeechRecognitionServer.cpp */,
</span><span class="cx">                          93D6B76C254B89580058DD3A /* SpeechRecognitionServer.h */,
</span><span class="cx">                          93D6B77A254C984D0058DD3A /* SpeechRecognitionServer.messages.in */,
</span><span class="lines">@@ -9547,6 +9563,8 @@
</span><span class="cx">                          33367639130C99DC006C9DE2 /* WKResourceCacheManager.h */,
</span><span class="cx">                          1ADE46B01954EC61000F7985 /* WKSessionStateRef.cpp */,
</span><span class="cx">                          1ADE46B11954EC61000F7985 /* WKSessionStateRef.h */,
</span><ins>+                               93D6B7B825534A120058DD3A /* WKSpeechRecognitionPermissionCallback.cpp */,
+                               93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */,
</ins><span class="cx">                           51F886A31F2C214A00C193EF /* WKTestingSupport.cpp */,
</span><span class="cx">                          51F886A41F2C214A00C193EF /* WKTestingSupport.h */,
</span><span class="cx">                          314888FE1D91B11D00377042 /* WKTextChecker.cpp */,
</span><span class="lines">@@ -11141,6 +11159,7 @@
</span><span class="cx">                          1A6D86C21DF75265007745E8 /* MachMessage.h in Headers */,
</span><span class="cx">                          BCC56F791159957D001CCAF9 /* MachPort.h in Headers */,
</span><span class="cx">                          1A24B5F311F531E800C38269 /* MachUtilities.h in Headers */,
</span><ins>+                               9342589A255B535A0059EEDD /* MediaPermissionUtilities.h in Headers */,
</ins><span class="cx">                           07E19EFC23D401F10094FFB4 /* MediaPlayerPrivateRemoteMessages.h in Headers */,
</span><span class="cx">                          07E19EFD23D401F10094FFB4 /* MediaPlayerPrivateRemoteMessagesReplies.h in Headers */,
</span><span class="cx">                          51933DEF1965EB31008AC3EA /* MenuUtilities.h in Headers */,
</span><span class="lines">@@ -11381,6 +11400,8 @@
</span><span class="cx">                          57BBEA6D22BC0BFE00273995 /* SOAuthorizationLoadPolicy.h in Headers */,
</span><span class="cx">                          576CA9D722B862180030143C /* SOAuthorizationNSURLExtras.h in Headers */,
</span><span class="cx">                          57FD318522B35169008D0E8B /* SOAuthorizationSession.h in Headers */,
</span><ins>+                               93D6B7B5255268D70058DD3A /* SpeechRecognitionPermissionManager.h in Headers */,
+                               93D6B7B4255268D50058DD3A /* SpeechRecognitionPermissionRequest.h in Headers */,
</ins><span class="cx">                           93D6B772254BB5190058DD3A /* SpeechRecognitionServer.h in Headers */,
</span><span class="cx">                          93D6B784254CCD0E0058DD3A /* SpeechRecognitionServerMessages.h in Headers */,
</span><span class="cx">                          93D6B785254CCD430058DD3A /* SpeechRecognitionServerMessagesReplies.h in Headers */,
</span><span class="lines">@@ -11996,6 +12017,7 @@
</span><span class="cx">                          513E462D1AD837560016234A /* WKSharingServicePickerDelegate.h in Headers */,
</span><span class="cx">                          93F549B41E3174B7000E7239 /* WKSnapshotConfiguration.h in Headers */,
</span><span class="cx">                          57FD318722B35170008D0E8B /* WKSOAuthorizationDelegate.h in Headers */,
</span><ins>+                               93D6B7B925534A170058DD3A /* WKSpeechRecognitionPermissionCallback.h in Headers */,
</ins><span class="cx">                           7A78FF32224191960096483E /* WKStorageAccessAlert.h in Headers */,
</span><span class="cx">                          BC407606124FF0270068F20A /* WKString.h in Headers */,
</span><span class="cx">                          BC40761A124FF0370068F20A /* WKStringCF.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebCoreSupportWebSpeechRecognitionConnectioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp 2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.cpp    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -59,10 +59,9 @@
</span><span class="cx">     m_clientMap.add(client.identifier(), makeWeakPtr(client));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebSpeechRecognitionConnection::start(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives)
</del><ins>+void WebSpeechRecognitionConnection::start(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives, WebCore::ClientOrigin&& clientOrigin)
</ins><span class="cx"> {
</span><del>-    WebCore::SpeechRecognitionRequestInfo info { clientIdentifier, lang, continuous, interimResults, maxAlternatives };
-    send(Messages::SpeechRecognitionServer::Start(info));
</del><ins>+    send(Messages::SpeechRecognitionServer::Start(clientIdentifier, lang, continuous, interimResults, maxAlternatives, WTFMove(clientOrigin)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebSpeechRecognitionConnection::stop(WebCore::SpeechRecognitionConnectionClientIdentifier clientIdentifier)
</span><span class="lines">@@ -80,7 +79,7 @@
</span><span class="cx">     send(Messages::SpeechRecognitionServer::Invalidate(clientIdentifier));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebSpeechRecognitionConnection::didReceiveUpdate(const WebCore::SpeechRecognitionUpdate& update)
</del><ins>+void WebSpeechRecognitionConnection::didReceiveUpdate(WebCore::SpeechRecognitionUpdate&& update)
</ins><span class="cx"> {
</span><span class="cx">     auto clientIdentifier = update.clientIdentifier();
</span><span class="cx">     if (!m_clientMap.contains(clientIdentifier))
</span></span></pre></div>
<a id="trunkSourceWebKitWebProcessWebCoreSupportWebSpeechRecognitionConnectionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.h      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -43,11 +43,11 @@
</span><span class="cx"> 
</span><span class="cx"> using SpeechRecognitionConnectionIdentifier = WebCore::PageIdentifier;
</span><span class="cx"> 
</span><del>-class WebSpeechRecognitionConnection : public WebCore::SpeechRecognitionConnection, private IPC::MessageReceiver, private IPC::MessageSender {
</del><ins>+class WebSpeechRecognitionConnection final : public WebCore::SpeechRecognitionConnection, private IPC::MessageReceiver, private IPC::MessageSender {
</ins><span class="cx"> public:
</span><span class="cx">     static Ref<WebSpeechRecognitionConnection> create(SpeechRecognitionConnectionIdentifier);
</span><span class="cx"> 
</span><del>-    void start(WebCore::SpeechRecognitionConnectionClientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives) final;
</del><ins>+    void start(WebCore::SpeechRecognitionConnectionClientIdentifier, const String& lang, bool continuous, bool interimResults, uint64_t maxAlternatives, WebCore::ClientOrigin&&) final;
</ins><span class="cx">     void stop(WebCore::SpeechRecognitionConnectionClientIdentifier) final;
</span><span class="cx">     void abort(WebCore::SpeechRecognitionConnectionClientIdentifier) final;
</span><span class="cx"> 
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx">     ~WebSpeechRecognitionConnection();
</span><span class="cx"> 
</span><span class="cx">     void registerClient(WebCore::SpeechRecognitionConnectionClient&) final;
</span><del>-    void didReceiveUpdate(const WebCore::SpeechRecognitionUpdate&) final;
</del><ins>+    void didReceiveUpdate(WebCore::SpeechRecognitionUpdate&&) final;
</ins><span class="cx">     void invalidate(WebCore::SpeechRecognitionConnectionClientIdentifier);
</span><span class="cx"> 
</span><span class="cx">     // IPC::MessageReceiver.
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/ChangeLog       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2020-11-13  Sihui Liu  <sihui_liu@apple.com>
+
+        Implement basic permission check for SpeechRecognition
+        https://bugs.webkit.org/show_bug.cgi?id=218476
+        <rdar://problem/71222638>
+
+        Reviewed by Youenn Fablet.
+
+        * MiniBrowser/mac/Info.plist:
+        * MobileMiniBrowser/MobileMiniBrowser/Info.plist:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm: Added.
+        (-[SpeechRecognitionPermissionUIDelegate _webView:requestSpeechRecognitionPermissionForOrigin:decisionHandler:]):
+        (-[SpeechRecognitionMessageHandler userContentController:didReceiveScriptMessage:]):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html: Added.
+        * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+        * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+        (WTR::TestRunner::setIsSpeechRecognitionPermissionGranted):
+        * WebKitTestRunner/InjectedBundle/TestRunner.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::decidePolicyForSpeechRecognitionPermissionRequest):
+        (WTR::TestController::completeSpeechRecognitionPermissionCheck):
+        (WTR::TestController::setIsSpeechRecognitionPermissionGranted):
+        (WTR::TestController::createWebViewWithOptions):
+        (WTR::TestController::resetStateToConsistentValues):
+        * WebKitTestRunner/TestController.h:
+        * WebKitTestRunner/TestInvocation.cpp:
+        (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+
</ins><span class="cx"> 2020-11-13  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [GPUProcess] Add basic GPUProcess crash handling for canvas
</span></span></pre></div>
<a id="trunkToolsMiniBrowsermacInfoplist"></a>
<div class="modfile"><h4>Modified: trunk/Tools/MiniBrowser/mac/Info.plist (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/MiniBrowser/mac/Info.plist   2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/MiniBrowser/mac/Info.plist      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -52,9 +52,11 @@
</span><span class="cx">                  <string>Editor</string>
</span><span class="cx">          </dict>
</span><span class="cx">  </array>
</span><del>-    <key>NSCameraUsageDescription</key>
-    <string>Recording video on behalf of websites</string>
-    <key>NSMicrophoneUsageDescription</key>
-    <string>Recording audio on behalf of websites</string>
</del><ins>+        <key>NSCameraUsageDescription</key>
+       <string>Recording video on behalf of websites</string>
+       <key>NSMicrophoneUsageDescription</key>
+       <string>Recording audio on behalf of websites</string>
+       <key>NSSpeechRecognitionUsageDescription</key>
+       <string>Recognizing captured audio on behalf of websites</string>
</ins><span class="cx"> </dict>
</span><span class="cx"> </plist>
</span></span></pre></div>
<a id="trunkToolsMobileMiniBrowserMobileMiniBrowserInfoplist"></a>
<div class="modfile"><h4>Modified: trunk/Tools/MobileMiniBrowser/MobileMiniBrowser/Info.plist (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/MobileMiniBrowser/MobileMiniBrowser/Info.plist       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/MobileMiniBrowser/MobileMiniBrowser/Info.plist  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -54,9 +54,11 @@
</span><span class="cx">          <key>NSAllowsArbitraryLoadsInWebContent</key>
</span><span class="cx">          <true/>
</span><span class="cx">  </dict>
</span><del>-    <key>NSCameraUsageDescription</key>
-    <string>Recording video on behalf of websites</string>
-    <key>NSMicrophoneUsageDescription</key>
-    <string>Recording audio on behalf of websites</string>
</del><ins>+        <key>NSCameraUsageDescription</key>
+       <string>Recording video on behalf of websites</string>
+       <key>NSMicrophoneUsageDescription</key>
+       <string>Recording audio on behalf of websites</string>
+       <key>NSSpeechRecognitionUsageDescription</key>
+       <string>Recognizing captured audio on behalf of websites</string>
</ins><span class="cx"> </dict>
</span><span class="cx"> </plist>
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj   2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -799,6 +799,8 @@
</span><span class="cx">          9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */; };
</span><span class="cx">          932AE53D1D371047005DFFAF /* focus-inputs.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93575C551D30366E000D604D /* focus-inputs.html */; };
</span><span class="cx">          933D631D1FCB76200032ECD6 /* Hasher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 933D631B1FCB76180032ECD6 /* Hasher.cpp */; };
</span><ins>+               9342589C255B609B0059EEDD /* SpeechRecognition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9342589B255B609A0059EEDD /* SpeechRecognition.mm */; };
+               9342589E255B6A120059EEDD /* speechrecognition-user-permission-persistence.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9342589D255B66A00059EEDD /* speechrecognition-user-permission-persistence.html */; };
</ins><span class="cx">           935786CC20F6A2700000CDFC /* IndexedDB.sqlite3-wal in Copy Resources */ = {isa = PBXBuildFile; fileRef = 934FA5C520F69FED0040DC1B /* IndexedDB.sqlite3-wal */; };
</span><span class="cx">          935786CD20F6A2910000CDFC /* IndexedDB.sqlite3 in Copy Resources */ = {isa = PBXBuildFile; fileRef = 934FA5C720F69FEE0040DC1B /* IndexedDB.sqlite3 */; };
</span><span class="cx">          935786CE20F6A2A10000CDFC /* IndexedDB.sqlite3-shm in Copy Resources */ = {isa = PBXBuildFile; fileRef = 934FA5C620F69FED0040DC1B /* IndexedDB.sqlite3-shm */; };
</span><span class="lines">@@ -1610,6 +1612,7 @@
</span><span class="cx">                          F4F405BD1D4C0D1C007A9707 /* skinny-autoplaying-video-with-audio.html in Copy Resources */,
</span><span class="cx">                          C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */,
</span><span class="cx">                          F4CFCDDA249FC9E400527482 /* SpaceOnly.otf in Copy Resources */,
</span><ins>+                               9342589E255B6A120059EEDD /* speechrecognition-user-permission-persistence.html in Copy Resources */,
</ins><span class="cx">                           E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */,
</span><span class="cx">                          515BE16F1D428BB100DD7C68 /* StoreBlobToBeDeleted.html in Copy Resources */,
</span><span class="cx">                          9BD6D3A21F7B218300BD4962 /* sunset-in-cupertino-100px.tiff in Copy Resources */,
</span><span class="lines">@@ -2400,6 +2403,8 @@
</span><span class="cx">          9329AA281DE3F81E003ABD07 /* TextBreakIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBreakIterator.cpp; sourceTree = "<group>"; };
</span><span class="cx">          9331407B17B4419000F083B1 /* DidNotHandleKeyDown.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidNotHandleKeyDown.cpp; sourceTree = "<group>"; };
</span><span class="cx">          933D631B1FCB76180032ECD6 /* Hasher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Hasher.cpp; sourceTree = "<group>"; };
</span><ins>+               9342589B255B609A0059EEDD /* SpeechRecognition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SpeechRecognition.mm; sourceTree = "<group>"; };
+               9342589D255B66A00059EEDD /* speechrecognition-user-permission-persistence.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "speechrecognition-user-permission-persistence.html"; sourceTree = "<group>"; };
</ins><span class="cx">           934FA5C520F69FED0040DC1B /* IndexedDB.sqlite3-wal */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IndexedDB.sqlite3-wal"; sourceTree = "<group>"; };
</span><span class="cx">          934FA5C620F69FED0040DC1B /* IndexedDB.sqlite3-shm */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IndexedDB.sqlite3-shm"; sourceTree = "<group>"; };
</span><span class="cx">          934FA5C720F69FEE0040DC1B /* IndexedDB.sqlite3 */ = {isa = PBXFileReference; lastKnownFileType = file; path = IndexedDB.sqlite3; sourceTree = "<group>"; };
</span><span class="lines">@@ -3380,6 +3385,7 @@
</span><span class="cx">                          37BCA61B1B596BA9002012CA /* ShouldOpenExternalURLsInNewWindowActions.mm */,
</span><span class="cx">                          2D9A53AE1B31FA8D0074D5AA /* ShrinkToFit.mm */,
</span><span class="cx">                          2DFF7B6C1DA487AF00814614 /* SnapshotStore.mm */,
</span><ins>+                               9342589B255B609A0059EEDD /* SpeechRecognition.mm */,
</ins><span class="cx">                           CDC0932D21C993440030C4B0 /* StopSuspendResumeAllMedia.mm */,
</span><span class="cx">                          414AD6852285D1B000777F2D /* StorageQuota.mm */,
</span><span class="cx">                          515BE1701D428BD100DD7C68 /* StoreBlobThenDelete.mm */,
</span><span class="lines">@@ -3900,6 +3906,7 @@
</span><span class="cx">                          4656A75720F9054F0002E21F /* SimpleServiceWorkerRegistrations-4.sqlite3 */,
</span><span class="cx">                          F4F405BB1D4C0CF8007A9707 /* skinny-autoplaying-video-with-audio.html */,
</span><span class="cx">                          F4CFCDD8249FC9D900527482 /* SpaceOnly.otf */,
</span><ins>+                               9342589D255B66A00059EEDD /* speechrecognition-user-permission-persistence.html */,
</ins><span class="cx">                           515BE16E1D4288FF00DD7C68 /* StoreBlobToBeDeleted.html */,
</span><span class="cx">                          9BD6D3A11F7B202100BD4962 /* sunset-in-cupertino-100px.tiff */,
</span><span class="cx">                          9BD6D3A01F7B202000BD4962 /* sunset-in-cupertino-200px.png */,
</span><span class="lines">@@ -5449,6 +5456,7 @@
</span><span class="cx">                          510A91F824D3622100BFD89C /* SonyDualShock3.mm in Sources */,
</span><span class="cx">                          51EB126424CA6B66000CB030 /* SonyDualShock4.mm in Sources */,
</span><span class="cx">                          7CCE7F151A411AE600447C4C /* SpacebarScrolling.cpp in Sources */,
</span><ins>+                               9342589C255B609B0059EEDD /* SpeechRecognition.mm in Sources */,
</ins><span class="cx">                           57F4AAA0208FAEF000A68E9E /* SSLKeyGenerator.mm in Sources */,
</span><span class="cx">                          83BC5AC020E6C0DF00F5879F /* StartLoadInDidFailProvisionalLoad.mm in Sources */,
</span><span class="cx">                          51EB126524CA6B66000CB030 /* SteelSeriesNimbus.mm in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaSpeechRecognitionmm"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm                         (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/SpeechRecognition.mm    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,106 @@
</span><ins>+/*
+ * Copyright (C) 2020 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.
+ */
+
+#import "config.h"
+
+#import "PlatformUtilities.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebView.h>
+#import <WebKit/WKWebViewConfiguration.h>
+#import <wtf/RetainPtr.h>
+
+static bool shouldGrantPermissionRequest = true;
+static bool permissionRequested = false;
+static bool receivedScriptMessage;
+static RetainPtr<WKScriptMessage> lastScriptMessage;
+
+@interface SpeechRecognitionPermissionUIDelegate : NSObject<WKUIDelegatePrivate>
+- (void)_webView:(WKWebView *)webView requestSpeechRecognitionPermissionForOrigin:(WKSecurityOrigin *)origin decisionHandler:(void (^)(BOOL))decisionHandler;
+@end
+
+@implementation SpeechRecognitionPermissionUIDelegate
+- (void)_webView:(WKWebView *)webView requestSpeechRecognitionPermissionForOrigin:(WKSecurityOrigin *)origin decisionHandler:(void (^)(BOOL))decisionHandler
+{
+    permissionRequested = true;
+    decisionHandler(shouldGrantPermissionRequest);
+}
+@end
+
+@interface SpeechRecognitionMessageHandler : NSObject <WKScriptMessageHandler>
+@end
+
+@implementation SpeechRecognitionMessageHandler
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    receivedScriptMessage = true;
+    lastScriptMessage = message;
+}
+@end
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, SpeechRecognitionUserPermissionPersistence)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto handler = adoptNS([[SpeechRecognitionMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
+    auto preferences = [configuration preferences];
+    preferences._mockCaptureDevicesEnabled = YES;
+    preferences._speechRecognitionEnabled = YES;
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    auto delegate = adoptNS([[SpeechRecognitionPermissionUIDelegate alloc] init]);
+    [webView setUIDelegate:delegate.get()];
+
+    shouldGrantPermissionRequest = false;
+    permissionRequested = false;
+    receivedScriptMessage = false;
+    [webView loadTestPageNamed:@"speechrecognition-user-permission-persistence"];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    EXPECT_WK_STREQ(@"Error: not-allowed - Permission check failed", [lastScriptMessage body]);
+    EXPECT_TRUE(permissionRequested);
+
+    // Permission result is remembered.
+    permissionRequested = false;
+    receivedScriptMessage = false;
+    [webView stringByEvaluatingJavaScript:@"start()"];
+    TestWebKitAPI::Util::run(&receivedScriptMessage);
+    EXPECT_WK_STREQ(@"Error: not-allowed - Permission check failed", [lastScriptMessage body]);
+    EXPECT_FALSE(permissionRequested);
+
+    // Permission result will be cleared after document changes.
+    [webView synchronouslyLoadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
+
+    shouldGrantPermissionRequest = true;
+    permissionRequested = false;
+    receivedScriptMessage = false;
+    [webView loadTestPageNamed:@"speechrecognition-user-permission-persistence"];
+    TestWebKitAPI::Util::run(&permissionRequested);
+    // Should not get error message as permission is granted.
+    EXPECT_FALSE(receivedScriptMessage);
+}
+
+} // namespace TestWebKitAPI
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitCocoaspeechrecognitionuserpermissionpersistencehtml"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html (0 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html                           (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/speechrecognition-user-permission-persistence.html      2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+<body onload="start()">
+<script>
+
+var speechRecognition = null;
+function start()
+{
+    stop();
+
+    speechRecognition = new SpeechRecognition();
+    speechRecognition.onerror = (event) => {
+        window.webkit.messageHandlers.testHandler.postMessage("Error: " + event.error + " - " +  event.message);
+    }
+    speechRecognition.onend = (event) => {
+        window.webkit.messageHandlers.testHandler.postMessage("End");
+    }
+    speechRecognition.start();
+}
+
+function stop()
+{
+    if (!speechRecognition)
+        return;
+
+    speechRecognition.stop();
+    speechRecognition = null;
+}
+
+</script>
+</body>
</ins></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleBindingsTestRunneridl"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl      2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl 2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -403,4 +403,7 @@
</span><span class="cx">     undefined setPrivateClickMeasurementOverrideTimerForTesting(boolean value);
</span><span class="cx">     undefined setPrivateClickMeasurementConversionURLForTesting(DOMString url);
</span><span class="cx">     undefined markPrivateClickMeasurementsAsExpiredForTesting();
</span><ins>+
+    // SpeechRecognition
+    undefined setIsSpeechRecognitionPermissionGranted(boolean value);
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleTestRunnercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp       2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp  2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -2069,6 +2069,11 @@
</span><span class="cx">     callTestRunnerCallback(DidSetAppBoundDomainsCallbackID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void TestRunner::setIsSpeechRecognitionPermissionGranted(bool granted)
+{
+    postSynchronousPageMessage("setIsSpeechRecognitionPermissionGranted", granted);
+}
+
</ins><span class="cx"> ALLOW_DEPRECATED_DECLARATIONS_END
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTR
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerInjectedBundleTestRunnerh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h 2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h    2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -515,6 +515,8 @@
</span><span class="cx">     void setPrivateClickMeasurementConversionURLForTesting(JSStringRef);
</span><span class="cx">     void markPrivateClickMeasurementsAsExpiredForTesting();
</span><span class="cx"> 
</span><ins>+    void setIsSpeechRecognitionPermissionGranted(bool);
+
</ins><span class="cx"> private:
</span><span class="cx">     TestRunner();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.cpp  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -62,6 +62,7 @@
</span><span class="cx"> #include <WebKit/WKProtectionSpace.h>
</span><span class="cx"> #include <WebKit/WKRetainPtr.h>
</span><span class="cx"> #include <WebKit/WKSecurityOriginRef.h>
</span><ins>+#include <WebKit/WKSpeechRecognitionPermissionCallback.h>
</ins><span class="cx"> #include <WebKit/WKTextChecker.h>
</span><span class="cx"> #include <WebKit/WKURL.h>
</span><span class="cx"> #include <WebKit/WKUserContentControllerRef.h>
</span><span class="lines">@@ -297,6 +298,21 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static void decidePolicyForSpeechRecognitionPermissionRequest(WKPageRef, WKSecurityOriginRef, WKSpeechRecognitionPermissionCallbackRef callback)
+{
+    TestController::singleton().completeSpeechRecognitionPermissionCheck(callback);
+}
+
+void TestController::completeSpeechRecognitionPermissionCheck(WKSpeechRecognitionPermissionCallbackRef callback)
+{
+    WKSpeechRecognitionPermissionCallbackComplete(callback, m_isSpeechRecognitionPermissionGranted);
+}
+
+void TestController::setIsSpeechRecognitionPermissionGranted(bool granted)
+{
+    m_isSpeechRecognitionPermissionGranted = granted;
+}
+
</ins><span class="cx"> WKPageRef TestController::createOtherPage(WKPageRef, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo)
</span><span class="cx"> {
</span><span class="cx">     PlatformWebView* parentView = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
</span><span class="lines">@@ -650,8 +666,8 @@
</span><span class="cx">     WKHTTPCookieStoreDeleteAllCookies(WKWebsiteDataStoreGetHTTPCookieStore(websiteDataStore()), nullptr, nullptr);
</span><span class="cx"> 
</span><span class="cx">     platformCreateWebView(configuration.get(), options);
</span><del>-    WKPageUIClientV14 pageUIClient = {
-        { 14, m_mainWebView.get() },
</del><ins>+    WKPageUIClientV15 pageUIClient = {
+        { 15, m_mainWebView.get() },
</ins><span class="cx">         0, // createNewPage_deprecatedForUseWithV0
</span><span class="cx">         0, // showPage
</span><span class="cx">         0, // close
</span><span class="lines">@@ -724,7 +740,8 @@
</span><span class="cx">         0, // didResignInputElementStrongPasswordAppearance
</span><span class="cx">         0, // requestStorageAccessConfirm
</span><span class="cx">         shouldAllowDeviceOrientationAndMotionAccess,
</span><del>-        runWebAuthenticationPanel
</del><ins>+        runWebAuthenticationPanel,
+        decidePolicyForSpeechRecognitionPermissionRequest
</ins><span class="cx">     };
</span><span class="cx">     WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base);
</span><span class="cx"> 
</span><span class="lines">@@ -1054,6 +1071,8 @@
</span><span class="cx">     m_serverTrustEvaluationCallbackCallsCount = 0;
</span><span class="cx">     m_shouldDismissJavaScriptAlertsAsynchronously = false;
</span><span class="cx"> 
</span><ins>+    setIsSpeechRecognitionPermissionGranted(true);
+
</ins><span class="cx">     auto loadAboutBlank = [this] {
</span><span class="cx">         m_doneResetting = false;
</span><span class="cx">         WKPageLoadURL(m_mainWebView->page(), blankURL());
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestController.h (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestController.h    2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/TestController.h       2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -351,6 +351,9 @@
</span><span class="cx"> 
</span><span class="cx">     WKURLRef currentTestURL() const;
</span><span class="cx"> 
</span><ins>+    void completeSpeechRecognitionPermissionCheck(WKSpeechRecognitionPermissionCallbackRef);
+    void setIsSpeechRecognitionPermissionGranted(bool);
+
</ins><span class="cx"> private:
</span><span class="cx">     WKRetainPtr<WKPageConfigurationRef> generatePageConfiguration(const TestOptions&);
</span><span class="cx">     WKRetainPtr<WKContextConfigurationRef> generateContextConfiguration(const TestOptions&) const;
</span><span class="lines">@@ -640,6 +643,8 @@
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">     bool m_hasSetApplicationBundleIdentifier { false };
</span><span class="cx"> #endif
</span><ins>+
+    bool m_isSpeechRecognitionPermissionGranted { false };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTR
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerTestInvocationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/TestInvocation.cpp (269809 => 269810)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/TestInvocation.cpp  2020-11-14 02:11:30 UTC (rev 269809)
+++ trunk/Tools/WebKitTestRunner/TestInvocation.cpp     2020-11-14 02:16:49 UTC (rev 269810)
</span><span class="lines">@@ -1345,6 +1345,11 @@
</span><span class="cx">         return nullptr;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (WKStringIsEqualToUTF8CString(messageName, "setIsSpeechRecognitionPermissionGranted")) {
+        TestController::singleton().setIsSpeechRecognitionPermissionGranted(booleanValue(messageBody));
+        return nullptr;
+    }
+
</ins><span class="cx">     ASSERT_NOT_REACHED();
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>