<!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>[206033] 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/206033">206033</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2016-09-16 11:14:04 -0700 (Fri, 16 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
https://bugs.webkit.org/show_bug.cgi?id=162009
&lt;rdar://problem/28086237&gt;

Reviewed by Tim Horton.

Source/WebKit2:

After inserting a text candidate, if the candidate ended with a soft space, the next space we insert should just
replace the soft space. This currently works because we leave the text insertion out of the list of
KeypressCommands sent to the web process and instead replace the soft space via WebPage::InsertTextAsync.
However, this means when the web process handles this keydown event, the current editor will not handle it,
since the list of key commands is empty despite the text and unmodified text being non-empty.

To fix this, when sending keydown or keyup events where we replace a soft space, we set the key event's text to
an empty string instead of a space. This allows us to return early in EventHandler::keyEvent and avoid the
codepath that tries to insert text into the current editor and (in the case of inserting a ' ') scrolls the
document if necessary. Since we've already handled text insertion via WebPage::InsertTextAsync, there is no need
to also dispatch the keypress to the editor.

Additionally, this patch addresses flickering in the candidates UI due to the fact that we're asynchronously
replacing the last soft space. During this operation, we select the range of the soft space and then insert the
new text. This causes a momentary range selection which the web process notifies the UI process about, prompting
us to hide the candidates list. To address this, we suppress the EditorStateChanged message fired from the web
process to the UI process while we're selecting the original range to replace.

This patch adds 3 new WebKit API tests.

* Shared/NativeWebKeyboardEvent.h:
* Shared/mac/NativeWebKeyboardEventMac.mm:
(WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
* Shared/mac/WebEventFactory.h:
* Shared/mac/WebEventFactory.mm:
(WebKit::textFromEvent):
(WebKit::unmodifiedTextFromEvent):
(WebKit::WebEventFactory::createWebKeyboardEvent):
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _handleAcceptedCandidate:]):
(-[WKWebView _didHandleAcceptedCandidate]):
(-[WKWebView _didUpdateCandidateListVisibility:]):
(-[WKWebView _forceRequestCandidates]):
(-[WKWebView _handleControlledElementIDResponse:]): Deleted.
* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/mac/WKView.mm:
(-[WKView _didHandleAcceptedCandidate]):
(-[WKView _didUpdateCandidateListVisibility:]):
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::forceRequestCandidatesForTesting):
(WebKit::WebViewImpl::becomeFirstResponder):
(WebKit::WebViewImpl::didHandleAcceptedCandidate):
(WebKit::WebViewImpl::insertText):
(WebKit::WebViewImpl::performKeyEquivalent):
(WebKit::WebViewImpl::keyUp):
(WebKit::WebViewImpl::keyDown):
(WebKit::WebViewImpl::flagsChanged):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::insertTextAsync):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::insertTextAsync):
(WebKit::WebPage::didChangeSelection):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

Adds 3 new text editing API tests covering candidate insertion, as well as support for testing candidates in
WKWebViews. Refactors common WKWebView helpers across both VideoControlsManager tests and the new
WKWebViewCandidateTests into a new utility class, TestWKWebView in TestWKWebView.mm, which is capable of
simulating mouse and keyboard events as well as waiting for JavaScript messages sent from the web process and
performing actions in response.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit/ios/audio-only.html:
* TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html:
* TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm:
(TestWebKitAPI::TEST):
(-[MessageHandler initWithMessage:handler:]): Deleted.
(-[MessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
(-[VideoControlsManagerTestWebView mouseDownAtPoint:]): Deleted.
(-[VideoControlsManagerTestWebView performAfterLoading:]): Deleted.
(-[VideoControlsManagerTestWebView callJavascriptFunction:]): Deleted.
(-[VideoControlsManagerTestWebView loadTestPageNamed:]): Deleted.
(-[VideoControlsManagerTestWebView performAfterReceivingMessage:action:]): Deleted.
* TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm: Added.
(-[TestCandidate initWithReplacementString:inRange:]):
(-[TestCandidate replacementString]):
(-[TestCandidate resultType]):
(-[TestCandidate range]):
(-[CandidateTestWebView insertCandidatesAndWaitForResponse:range:]):
(-[CandidateTestWebView _didHandleAcceptedCandidate]):
(-[CandidateTestWebView expectCandidateListVisibilityUpdates:whenPerformingActions:]):
(-[CandidateTestWebView _didUpdateCandidateListVisibility:]):
(TEST):
* TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html: Added.
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html:
* TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html:
* TestWebKitAPI/mac/TestWKWebViewMac.h: Added.
* TestWebKitAPI/mac/TestWKWebViewMac.mm: Added.
(-[TestMessageHandler initWithMessage:handler:]):
(-[TestMessageHandler userContentController:didReceiveScriptMessage:]):
(-[TestWKWebView mouseDownAtPoint:]):
(-[TestWKWebView performAfterReceivingMessage:action:]):
(-[TestWKWebView loadTestPageNamed:]):
(-[TestWKWebView typeCharacter:]):
(-[TestWKWebView stringByEvaluatingJavaScript:]):
(-[TestWKWebView waitForMessage:]):
(-[TestWKWebView performAfterLoading:]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2SharedNativeWebKeyboardEventh">trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h</a></li>
<li><a href="#trunkSourceWebKit2SharedmacNativeWebKeyboardEventMacmm">trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm</a></li>
<li><a href="#trunkSourceWebKit2SharedmacWebEventFactoryh">trunk/Source/WebKit2/Shared/mac/WebEventFactory.h</a></li>
<li><a href="#trunkSourceWebKit2SharedmacWebEventFactorymm">trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKWebViewPrivateh">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPImacWKViewmm">trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebViewImplh">trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebViewImplmm">trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxycpp">trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxyh">trunk/Source/WebKit2/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagecpp">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPageh">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagemessagesin">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitiosaudioonlyhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitiosvideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKitiosvideowithoutaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaVideoControlsManagermm">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoaautoplayingvideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoachangevideosourceonclickhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoachangevideosourceonendhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoafullsizeautoplayingvideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideohidescontrolsafterseektoendhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideomutesonplayinghtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideooffscreenhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoplayingscrollawayhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoseekafterendinghtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoseektobeginningandplayafterendinghtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideowithoutaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosautoplayingclicktopausehtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosautoplayingscrolltovideohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideospausedvideohidescontrolshtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosplayingmutedvideohidescontrolshtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosplayingvideokeepscontrolshtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoswithaudioautoplayhtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoaskinnyautoplayingvideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoawideautoplayingvideowithaudiohtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2CocoaWKWebViewCandidateTestsmm">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoainputfieldinscrollabledocumenthtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html</a></li>
<li><a href="#trunkToolsTestWebKitAPImacTestWKWebViewMach">trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h</a></li>
<li><a href="#trunkToolsTestWebKitAPImacTestWKWebViewMacmm">trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/ChangeLog        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -1,3 +1,68 @@
</span><ins>+2016-09-16  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
+        https://bugs.webkit.org/show_bug.cgi?id=162009
+        &lt;rdar://problem/28086237&gt;
+
+        Reviewed by Tim Horton.
+
+        After inserting a text candidate, if the candidate ended with a soft space, the next space we insert should just
+        replace the soft space. This currently works because we leave the text insertion out of the list of
+        KeypressCommands sent to the web process and instead replace the soft space via WebPage::InsertTextAsync.
+        However, this means when the web process handles this keydown event, the current editor will not handle it,
+        since the list of key commands is empty despite the text and unmodified text being non-empty.
+
+        To fix this, when sending keydown or keyup events where we replace a soft space, we set the key event's text to
+        an empty string instead of a space. This allows us to return early in EventHandler::keyEvent and avoid the
+        codepath that tries to insert text into the current editor and (in the case of inserting a ' ') scrolls the
+        document if necessary. Since we've already handled text insertion via WebPage::InsertTextAsync, there is no need
+        to also dispatch the keypress to the editor.
+
+        Additionally, this patch addresses flickering in the candidates UI due to the fact that we're asynchronously
+        replacing the last soft space. During this operation, we select the range of the soft space and then insert the
+        new text. This causes a momentary range selection which the web process notifies the UI process about, prompting
+        us to hide the candidates list. To address this, we suppress the EditorStateChanged message fired from the web
+        process to the UI process while we're selecting the original range to replace.
+
+        This patch adds 3 new WebKit API tests.
+
+        * Shared/NativeWebKeyboardEvent.h:
+        * Shared/mac/NativeWebKeyboardEventMac.mm:
+        (WebKit::NativeWebKeyboardEvent::NativeWebKeyboardEvent):
+        * Shared/mac/WebEventFactory.h:
+        * Shared/mac/WebEventFactory.mm:
+        (WebKit::textFromEvent):
+        (WebKit::unmodifiedTextFromEvent):
+        (WebKit::WebEventFactory::createWebKeyboardEvent):
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _handleAcceptedCandidate:]):
+        (-[WKWebView _didHandleAcceptedCandidate]):
+        (-[WKWebView _didUpdateCandidateListVisibility:]):
+        (-[WKWebView _forceRequestCandidates]):
+        (-[WKWebView _handleControlledElementIDResponse:]): Deleted.
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView _didHandleAcceptedCandidate]):
+        (-[WKView _didUpdateCandidateListVisibility:]):
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::forceRequestCandidatesForTesting):
+        (WebKit::WebViewImpl::becomeFirstResponder):
+        (WebKit::WebViewImpl::didHandleAcceptedCandidate):
+        (WebKit::WebViewImpl::insertText):
+        (WebKit::WebViewImpl::performKeyEquivalent):
+        (WebKit::WebViewImpl::keyUp):
+        (WebKit::WebViewImpl::keyDown):
+        (WebKit::WebViewImpl::flagsChanged):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::insertTextAsync):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::insertTextAsync):
+        (WebKit::WebPage::didChangeSelection):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
</ins><span class="cx"> 2016-09-16  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add support for enum class parameters in the message generator
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedNativeWebKeyboardEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/NativeWebKeyboardEvent.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx"> class NativeWebKeyboardEvent : public WebKeyboardEvent {
</span><span class="cx"> public:
</span><span class="cx"> #if USE(APPKIT)
</span><del>-    NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
</del><ins>+    NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
</ins><span class="cx"> #elif PLATFORM(GTK)
</span><span class="cx">     NativeWebKeyboardEvent(const NativeWebKeyboardEvent&amp;);
</span><span class="cx">     NativeWebKeyboardEvent(GdkEvent*, const WebCore::CompositionResults&amp;, InputMethodFilter::EventFakedForComposition, Vector&lt;String&gt;&amp;&amp; commands);
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedmacNativeWebKeyboardEventMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -35,8 +35,8 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><del>-NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector&lt;KeypressCommand&gt;&amp; commands)
-    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, handledByInputMethod, commands))
</del><ins>+NativeWebKeyboardEvent::NativeWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, bool replacesSoftSpace, const Vector&lt;KeypressCommand&gt;&amp; commands)
+    : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event, handledByInputMethod, replacesSoftSpace, commands))
</ins><span class="cx">     , m_nativeEvent(event)
</span><span class="cx"> {
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedmacWebEventFactoryh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/mac/WebEventFactory.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/mac/WebEventFactory.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/WebEventFactory.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx"> #if USE(APPKIT)
</span><span class="cx">     static WebMouseEvent createWebMouseEvent(NSEvent *, NSEvent *lastPressureEvent, NSView *windowView);
</span><span class="cx">     static WebWheelEvent createWebWheelEvent(NSEvent *, NSView *windowView);
</span><del>-    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
</del><ins>+    static WebKeyboardEvent createWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
</ins><span class="cx">     static bool shouldBeHandledAsContextClick(const WebCore::PlatformMouseEvent&amp;);
</span><span class="cx"> #endif // USE(APPKIT)
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedmacWebEventFactorymm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/Shared/mac/WebEventFactory.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -236,8 +236,10 @@
</span><span class="cx">     return static_cast&lt;WebWheelEvent::Phase&gt;(phase);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline String textFromEvent(NSEvent* event)
</del><ins>+static inline String textFromEvent(NSEvent* event, bool replacesSoftSpace)
</ins><span class="cx"> {
</span><ins>+    if (replacesSoftSpace)
+        return emptyString();
</ins><span class="cx"> #pragma clang diagnostic push
</span><span class="cx"> #pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
</span><span class="cx">     if ([event type] == NSFlagsChanged)
</span><span class="lines">@@ -246,8 +248,10 @@
</span><span class="cx">     return String([event characters]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static inline String unmodifiedTextFromEvent(NSEvent* event)
</del><ins>+static inline String unmodifiedTextFromEvent(NSEvent* event, bool replacesSoftSpace)
</ins><span class="cx"> {
</span><ins>+    if (replacesSoftSpace)
+        return emptyString();
</ins><span class="cx"> #pragma clang diagnostic push
</span><span class="cx"> #pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
</span><span class="cx">     if ([event type] == NSFlagsChanged)
</span><span class="lines">@@ -457,11 +461,11 @@
</span><span class="cx">     return WebWheelEvent(WebEvent::Wheel, IntPoint(position), IntPoint(globalPosition), FloatSize(deltaX, deltaY), FloatSize(wheelTicksX, wheelTicksY), granularity, directionInvertedFromDevice, phase, momentumPhase, hasPreciseScrollingDeltas, scrollCount, unacceleratedScrollingDelta, modifiers, timestamp);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands)
</del><ins>+WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(NSEvent *event, bool handledByInputMethod, bool replacesSoftSpace, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands)
</ins><span class="cx"> {
</span><span class="cx">     WebEvent::Type type             = isKeyUpEvent(event) ? WebEvent::KeyUp : WebEvent::KeyDown;
</span><del>-    String text                     = textFromEvent(event);
-    String unmodifiedText           = unmodifiedTextFromEvent(event);
</del><ins>+    String text                     = textFromEvent(event, replacesSoftSpace);
+    String unmodifiedText           = unmodifiedTextFromEvent(event, replacesSoftSpace);
</ins><span class="cx">     String keyIdentifier            = keyIdentifierForKeyEvent(event);
</span><span class="cx">     int windowsVirtualKeyCode       = windowsKeyCodeForKeyEvent(event);
</span><span class="cx">     int nativeVirtualKeyCode        = [event keyCode];
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -4564,6 +4564,28 @@
</span><span class="cx"> {
</span><span class="cx">     // Overridden by subclasses.
</span><span class="cx"> }
</span><ins>+
+- (void)_handleAcceptedCandidate:(NSTextCheckingResult *)candidate
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101200
+    _impl-&gt;handleAcceptedCandidate(candidate);
+#endif
+}
+
+- (void)_didHandleAcceptedCandidate
+{
+    // Overridden by subclasses.
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+    // Overridden by subclasses.
+}
+
+- (void)_forceRequestCandidates
+{
+    _impl-&gt;forceRequestCandidatesForTesting();
+}
</ins><span class="cx"> #endif // PLATFORM(MAC)
</span><span class="cx"> 
</span><span class="cx"> // Execute the supplied block after the next transaction from the WebProcess.
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKWebViewPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -273,6 +273,10 @@
</span><span class="cx"> @property (nonatomic, readonly) BOOL _hasActiveVideoForControlsManager WK_API_AVAILABLE(macosx(10.12));
</span><span class="cx"> - (void)_requestControlledElementID WK_API_AVAILABLE(macosx(WK_MAC_TBA));
</span><span class="cx"> - (void)_handleControlledElementIDResponse:(NSString *)identifier WK_API_AVAILABLE(macosx(WK_MAC_TBA));
</span><ins>+- (void)_handleAcceptedCandidate:(NSTextCheckingResult *)candidate WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_didHandleAcceptedCandidate WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_forceRequestCandidates WK_API_AVAILABLE(macosx(WK_MAC_TBA));
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible WK_API_AVAILABLE(macosx(WK_MAC_TBA));
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> - (void)_doAfterNextPresentationUpdate:(void (^)(void))updateBlock WK_API_AVAILABLE(macosx(10.12), ios(10.0));
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPImacWKViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -969,6 +969,14 @@
</span><span class="cx">     [self _gestureEventWasNotHandledByWebCore:event];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)_didHandleAcceptedCandidate
+{
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+}
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation WKView (Private)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebViewImplh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -84,6 +84,8 @@
</span><span class="cx"> @optional
</span><span class="cx"> - (void)_web_didAddMediaControlsManager:(id)controlsManager;
</span><span class="cx"> - (void)_web_didRemoveMediaControlsManager;
</span><ins>+- (void)_didHandleAcceptedCandidate;
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible;
</ins><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="lines">@@ -478,6 +480,7 @@
</span><span class="cx">     void rightMouseUp(NSEvent *);
</span><span class="cx"> 
</span><span class="cx">     void updateWebViewImplAdditions();
</span><ins>+    void forceRequestCandidatesForTesting();
</ins><span class="cx">     bool shouldRequestCandidates() const;
</span><span class="cx">     void showCandidates(NSArray *candidates, NSString *, NSRect rectOfTypedString, NSRange selectedRange, NSView *, void (^completionHandler)(NSTextCheckingResult *acceptedCandidate));
</span><span class="cx">     void webViewImplAdditionsWillDestroyView();
</span><span class="lines">@@ -649,6 +652,7 @@
</span><span class="cx">     bool m_isHandlingAcceptedCandidate { false };
</span><span class="cx">     bool m_requiresUserActionForEditingControlsManager { false };
</span><span class="cx">     bool m_editableElementIsFocused { false };
</span><ins>+    bool m_isTextInsertionReplacingSoftSpace { false };
</ins><span class="cx"> };
</span><span class="cx">     
</span><span class="cx"> } // namespace WebKit
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebViewImplmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -441,6 +441,10 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebViewImpl::forceRequestCandidatesForTesting()
+{
+}
+
</ins><span class="cx"> bool WebViewImpl::shouldRequestCandidates() const
</span><span class="cx"> {
</span><span class="cx">     return false;
</span><span class="lines">@@ -620,7 +624,7 @@
</span><span class="cx">         if ([event type] == NSKeyDown || [event type] == NSKeyUp)
</span><span class="cx">             keyboardEvent = event;
</span><span class="cx"> #pragma clang diagnostic pop
</span><del>-        m_page-&gt;setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, { }), [](WebKit::CallbackBase::Error) { });
</del><ins>+        m_page-&gt;setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, false, { }), [](WebKit::CallbackBase::Error) { });
</ins><span class="cx">     }
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="lines">@@ -2436,6 +2440,8 @@
</span><span class="cx"> void WebViewImpl::didHandleAcceptedCandidate()
</span><span class="cx"> {
</span><span class="cx">     m_isHandlingAcceptedCandidate = false;
</span><ins>+
+    [m_view _didHandleAcceptedCandidate];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebViewImpl::videoControlsManagerDidChange()
</span><span class="lines">@@ -3567,11 +3573,11 @@
</span><span class="cx">     } else
</span><span class="cx">         text = string;
</span><span class="cx"> 
</span><del>-    BOOL needToRemoveSoftSpace = NO;
</del><ins>+    m_isTextInsertionReplacingSoftSpace = false;
</ins><span class="cx"> #if HAVE(ADVANCED_SPELL_CHECKING)
</span><span class="cx">     if (m_softSpaceRange.location != NSNotFound &amp;&amp; (replacementRange.location == NSMaxRange(m_softSpaceRange) || replacementRange.location == NSNotFound) &amp;&amp; replacementRange.length == 0 &amp;&amp; [[NSSpellChecker sharedSpellChecker] deletesAutospaceBeforeString:text language:nil]) {
</span><span class="cx">         replacementRange = m_softSpaceRange;
</span><del>-        needToRemoveSoftSpace = YES;
</del><ins>+        m_isTextInsertionReplacingSoftSpace = true;
</ins><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx">     m_softSpaceRange = NSMakeRange(NSNotFound, 0);
</span><span class="lines">@@ -3582,7 +3588,7 @@
</span><span class="cx">     // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
</span><span class="cx">     // then we also execute it immediately, as there will be no other chance.
</span><span class="cx">     Vector&lt;WebCore::KeypressCommand&gt;* keypressCommands = m_collectedKeypressCommands;
</span><del>-    if (keypressCommands &amp;&amp; !needToRemoveSoftSpace) {
</del><ins>+    if (keypressCommands &amp;&amp; !m_isTextInsertionReplacingSoftSpace) {
</ins><span class="cx">         ASSERT(replacementRange.location == NSNotFound);
</span><span class="cx">         WebCore::KeypressCommand command(&quot;insertText:&quot;, text);
</span><span class="cx">         keypressCommands-&gt;append(command);
</span><span class="lines">@@ -3596,7 +3602,7 @@
</span><span class="cx">     if (!dictationAlternatives.isEmpty())
</span><span class="cx">         m_page-&gt;insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
</span><span class="cx">     else
</span><del>-        m_page-&gt;insertTextAsync(eventText, replacementRange, registerUndoGroup, needToRemoveSoftSpace ? EditingRangeIsRelativeTo::Paragraph : EditingRangeIsRelativeTo::EditableRoot);
</del><ins>+        m_page-&gt;insertTextAsync(eventText, replacementRange, registerUndoGroup, m_isTextInsertionReplacingSoftSpace ? EditingRangeIsRelativeTo::Paragraph : EditingRangeIsRelativeTo::EditableRoot, m_isTextInsertionReplacingSoftSpace);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebViewImpl::selectedRangeWithCompletionHandler(void(^completionHandlerPtr)(NSRange selectedRange))
</span><span class="lines">@@ -3870,7 +3876,7 @@
</span><span class="cx">     // FIXME: Why is the firstResponder check needed?
</span><span class="cx">     if (m_view == m_view.window.firstResponder) {
</span><span class="cx">         interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
</span><del>-            m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
</del><ins>+            m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, false, commands));
</ins><span class="cx">         });
</span><span class="cx">         return YES;
</span><span class="cx">     }
</span><span class="lines">@@ -3885,9 +3891,10 @@
</span><span class="cx"> 
</span><span class="cx">     LOG(TextInput, &quot;keyUp:%p %@&quot;, event, event);
</span><span class="cx"> 
</span><ins>+    m_isTextInsertionReplacingSoftSpace = false;
</ins><span class="cx">     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
</span><span class="cx">         ASSERT(!handledByInputMethod || commands.isEmpty());
</span><del>-        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
</del><ins>+        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -3912,9 +3919,10 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    m_isTextInsertionReplacingSoftSpace = false;
</ins><span class="cx">     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
</span><span class="cx">         ASSERT(!handledByInputMethod || commands.isEmpty());
</span><del>-        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
</del><ins>+        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -3930,7 +3938,7 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
</span><del>-        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
</del><ins>+        m_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, false, commands));
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -6145,12 +6145,12 @@
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx"> 
</span><del>-void WebPageProxy::insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo)
</del><ins>+void WebPageProxy::insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup, EditingRangeIsRelativeTo editingRangeIsRelativeTo, bool suppressSelectionUpdate)
</ins><span class="cx"> {
</span><span class="cx">     if (!isValid())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, registerUndoGroup, static_cast&lt;uint32_t&gt;(editingRangeIsRelativeTo)), m_pageID);
</del><ins>+    process().send(Messages::WebPage::InsertTextAsync(text, replacementRange, registerUndoGroup, static_cast&lt;uint32_t&gt;(editingRangeIsRelativeTo), suppressSelectionUpdate), m_pageID);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::getMarkedRangeAsync(std::function&lt;void (EditingRange, CallbackBase::Error)&gt; callbackFunction)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -564,7 +564,7 @@
</span><span class="cx">     void setAcceleratedCompositingRootLayer(LayerOrView*);
</span><span class="cx">     LayerOrView* acceleratedCompositingRootLayer() const;
</span><span class="cx"> 
</span><del>-    void insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup = false, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot);
</del><ins>+    void insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup = false, EditingRangeIsRelativeTo = EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
</ins><span class="cx">     void getMarkedRangeAsync(std::function&lt;void (EditingRange, CallbackBase::Error)&gt;);
</span><span class="cx">     void getSelectedRangeAsync(std::function&lt;void (EditingRange, CallbackBase::Error)&gt;);
</span><span class="cx">     void characterIndexForPointAsync(const WebCore::IntPoint&amp;, std::function&lt;void (uint64_t, CallbackBase::Error)&gt;);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -4610,14 +4610,16 @@
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx"> 
</span><del>-void WebPage::insertTextAsync(const String&amp; text, const EditingRange&amp; replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo)
</del><ins>+void WebPage::insertTextAsync(const String&amp; text, const EditingRange&amp; replacementEditingRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
</ins><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="cx"> 
</span><span class="cx">     if (replacementEditingRange.location != notFound) {
</span><span class="cx">         RefPtr&lt;Range&gt; replacementRange = rangeFromEditingRange(frame, replacementEditingRange, static_cast&lt;EditingRangeIsRelativeTo&gt;(editingRangeIsRelativeTo));
</span><del>-        if (replacementRange)
</del><ins>+        if (replacementRange) {
+            TemporaryChange&lt;bool&gt; isSelectingTextWhileInsertingAsynchronously(m_isSelectingTextWhileInsertingAsynchronously, suppressSelectionUpdate);
</ins><span class="cx">             frame.selection().setSelection(VisibleSelection(*replacementRange, SEL_DEFAULT_AFFINITY));
</span><ins>+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (registerUndoGroup)
</span><span class="lines">@@ -4842,6 +4844,11 @@
</span><span class="cx">     if (m_isGettingDictionaryPopupInfo)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    // Similarly, we don't want to propagate changes to the web process when inserting text asynchronously, since we will
+    // end up with a range selection very briefly right before inserting the text.
+    if (m_isSelectingTextWhileInsertingAsynchronously)
+        return;
+
</ins><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="cx">     FrameView* view = frame.view();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -666,7 +666,7 @@
</span><span class="cx">     
</span><span class="cx">     void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String&amp; textInput);
</span><span class="cx"> 
</span><del>-    void insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup = false, uint32_t editingRangeIsRelativeTo = (uint32_t)EditingRangeIsRelativeTo::EditableRoot);
</del><ins>+    void insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, bool registerUndoGroup = false, uint32_t editingRangeIsRelativeTo = (uint32_t)EditingRangeIsRelativeTo::EditableRoot, bool suppressSelectionUpdate = false);
</ins><span class="cx">     void getMarkedRangeAsync(uint64_t callbackID);
</span><span class="cx">     void getSelectedRangeAsync(uint64_t callbackID);
</span><span class="cx">     void characterIndexForPointAsync(const WebCore::IntPoint&amp;, uint64_t callbackID);
</span><span class="lines">@@ -1488,6 +1488,7 @@
</span><span class="cx">     bool m_shouldDispatchFakeMouseMoveEvents;
</span><span class="cx">     bool m_isEditorStateMissingPostLayoutData { false };
</span><span class="cx">     bool m_isGettingDictionaryPopupInfo { false };
</span><ins>+    bool m_isSelectingTextWhileInsertingAsynchronously { false };
</ins><span class="cx"> 
</span><span class="cx">     enum class EditorStateIsContentEditable { No, Yes, Unset };
</span><span class="cx">     mutable EditorStateIsContentEditable m_lastEditorStateWasContentEditable { EditorStateIsContentEditable::Unset };
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagemessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -366,7 +366,7 @@
</span><span class="cx">     ShouldDelayWindowOrderingEvent(WebKit::WebMouseEvent event) -&gt; (bool result)
</span><span class="cx">     AcceptsFirstMouse(int eventNumber, WebKit::WebMouseEvent event) -&gt; (bool result)
</span><span class="cx"> 
</span><del>-    InsertTextAsync(String text, struct WebKit::EditingRange replacementRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo)
</del><ins>+    InsertTextAsync(String text, struct WebKit::EditingRange replacementRange, bool registerUndoGroup, uint32_t editingRangeIsRelativeTo, bool suppressSelectionUpdate)
</ins><span class="cx">     GetMarkedRangeAsync(uint64_t callbackID)
</span><span class="cx">     GetSelectedRangeAsync(uint64_t callbackID)
</span><span class="cx">     CharacterIndexForPointAsync(WebCore::IntPoint point, uint64_t callbackID);
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/ChangeLog        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2016-09-16  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        Inserting a space after inserting an accepted candidate scrolls the document and causes a flicker
+        https://bugs.webkit.org/show_bug.cgi?id=162009
+        &lt;rdar://problem/28086237&gt;
+
+        Reviewed by Tim Horton.
+
+        Adds 3 new text editing API tests covering candidate insertion, as well as support for testing candidates in
+        WKWebViews. Refactors common WKWebView helpers across both VideoControlsManager tests and the new
+        WKWebViewCandidateTests into a new utility class, TestWKWebView in TestWKWebView.mm, which is capable of
+        simulating mouse and keyboard events as well as waiting for JavaScript messages sent from the web process and
+        performing actions in response.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit/ios/audio-only.html:
+        * TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm:
+        (TestWebKitAPI::TEST):
+        (-[MessageHandler initWithMessage:handler:]): Deleted.
+        (-[MessageHandler userContentController:didReceiveScriptMessage:]): Deleted.
+        (-[VideoControlsManagerTestWebView mouseDownAtPoint:]): Deleted.
+        (-[VideoControlsManagerTestWebView performAfterLoading:]): Deleted.
+        (-[VideoControlsManagerTestWebView callJavascriptFunction:]): Deleted.
+        (-[VideoControlsManagerTestWebView loadTestPageNamed:]): Deleted.
+        (-[VideoControlsManagerTestWebView performAfterReceivingMessage:action:]): Deleted.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm: Added.
+        (-[TestCandidate initWithReplacementString:inRange:]):
+        (-[TestCandidate replacementString]):
+        (-[TestCandidate resultType]):
+        (-[TestCandidate range]):
+        (-[CandidateTestWebView insertCandidatesAndWaitForResponse:range:]):
+        (-[CandidateTestWebView _didHandleAcceptedCandidate]):
+        (-[CandidateTestWebView expectCandidateListVisibilityUpdates:whenPerformingActions:]):
+        (-[CandidateTestWebView _didUpdateCandidateListVisibility:]):
+        (TEST):
+        * TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html: Added.
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html:
+        * TestWebKitAPI/mac/TestWKWebViewMac.h: Added.
+        * TestWebKitAPI/mac/TestWKWebViewMac.mm: Added.
+        (-[TestMessageHandler initWithMessage:handler:]):
+        (-[TestMessageHandler userContentController:didReceiveScriptMessage:]):
+        (-[TestWKWebView mouseDownAtPoint:]):
+        (-[TestWKWebView performAfterReceivingMessage:action:]):
+        (-[TestWKWebView loadTestPageNamed:]):
+        (-[TestWKWebView typeCharacter:]):
+        (-[TestWKWebView stringByEvaluatingJavaScript:]):
+        (-[TestWKWebView waitForMessage:]):
+        (-[TestWKWebView performAfterLoading:]):
+
</ins><span class="cx"> 2016-09-14  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [media-source] fix imported/w3c/web-platform-tests/media-source/mediasource-duration.html
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -78,6 +78,9 @@
</span><span class="cx">                 2EFF06C31D88621E0004BB30 /* large-video-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C21D8862120004BB30 /* large-video-offscreen.html */; };
</span><span class="cx">                 2EFF06C51D8867760004BB30 /* change-video-source-on-click.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */; };
</span><span class="cx">                 2EFF06C71D886A580004BB30 /* change-video-source-on-end.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */; };
</span><ins>+                2EFF06CD1D8A429A0004BB30 /* input-field-in-scrollable-document.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */; };
+                2EFF06D41D8AEDBB0004BB30 /* TestWKWebViewMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */; };
+                2EFF06D71D8AF34A0004BB30 /* WKWebViewCandidateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */; };
</ins><span class="cx">                 33BE5AF9137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */; };
</span><span class="cx">                 33DC8912141955FE00747EF7 /* simple-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 33DC890E1419539300747EF7 /* simple-iframe.html */; };
</span><span class="cx">                 33DC89141419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33DC89131419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp */; };
</span><span class="lines">@@ -541,6 +544,7 @@
</span><span class="cx">                         dstPath = TestWebKitAPI.resources;
</span><span class="cx">                         dstSubfolderSpec = 7;
</span><span class="cx">                         files = (
</span><ins>+                                2EFF06CD1D8A429A0004BB30 /* input-field-in-scrollable-document.html in Copy Resources */,
</ins><span class="cx">                                 2EFF06C71D886A580004BB30 /* change-video-source-on-end.html in Copy Resources */,
</span><span class="cx">                                 2EFF06C51D8867760004BB30 /* change-video-source-on-click.html in Copy Resources */,
</span><span class="cx">                                 2EFF06C31D88621E0004BB30 /* large-video-offscreen.html in Copy Resources */,
</span><span class="lines">@@ -789,6 +793,10 @@
</span><span class="cx">                 2EFF06C21D8862120004BB30 /* large-video-offscreen.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;large-video-offscreen.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;change-video-source-on-click.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;change-video-source-on-end.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = &quot;input-field-in-scrollable-document.html&quot;; sourceTree = &quot;&lt;group&gt;&quot;; };
+                2EFF06D21D8AEDBB0004BB30 /* TestWKWebViewMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestWKWebViewMac.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestWKWebViewMac.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
+                2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewCandidateTests.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreventEmptyUserAgent.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 33BE5AF4137B5A6C00705813 /* MouseMoveAfterCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 33BE5AF8137B5AAE00705813 /* MouseMoveAfterCrash_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseMoveAfterCrash_Bundle.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -1375,6 +1383,7 @@
</span><span class="cx">                                 37B47E2E1D64E7CA005F4EFF /* WKObject.mm */,
</span><span class="cx">                                 2D00065D1C1F58940088E6A7 /* WKPDFViewResizeCrash.mm */,
</span><span class="cx">                                 5E4B1D2C1D404C6100053621 /* WKScrollViewDelegateCrash.mm */,
</span><ins>+                                2EFF06D61D8AF34A0004BB30 /* WKWebViewCandidateTests.mm */,
</ins><span class="cx">                                 7C417F311D19E14800B8EF53 /* WKWebViewDefaultNavigationDelegate.mm */,
</span><span class="cx">                                 0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */,
</span><span class="cx">                                 9984FACA1CFFAEEE008D198C /* WKWebViewTextInput.mm */,
</span><span class="lines">@@ -1464,6 +1473,7 @@
</span><span class="cx">                 A16F66B81C40E9E100BD4D24 /* Resources */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                2EFF06CC1D8A42910004BB30 /* input-field-in-scrollable-document.html */,
</ins><span class="cx">                                 2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */,
</span><span class="cx">                                 2EFF06C41D8867700004BB30 /* change-video-source-on-click.html */,
</span><span class="cx">                                 2EFF06C21D8862120004BB30 /* large-video-offscreen.html */,
</span><span class="lines">@@ -1819,6 +1829,8 @@
</span><span class="cx">                                 C081224413FC19EC00DC39AE /* SyntheticBackingScaleFactorWindow.m */,
</span><span class="cx">                                 29AB8AA3164C7A9300D49BEC /* TestBrowsingContextLoadDelegate.h */,
</span><span class="cx">                                 29AB8AA2164C7A9300D49BEC /* TestBrowsingContextLoadDelegate.mm */,
</span><ins>+                                2EFF06D21D8AEDBB0004BB30 /* TestWKWebViewMac.h */,
+                                2EFF06D31D8AEDBB0004BB30 /* TestWKWebViewMac.mm */,
</ins><span class="cx">                                 C08587BE13FE956C001EF4E5 /* WebKitAgnosticTest.h */,
</span><span class="cx">                                 C08587BD13FE956C001EF4E5 /* WebKitAgnosticTest.mm */,
</span><span class="cx">                         );
</span><span class="lines">@@ -2342,6 +2354,7 @@
</span><span class="cx">                                 7CCE7EFB1A411AE600447C4C /* InjectedBundleBasic.cpp in Sources */,
</span><span class="cx">                                 7CCE7EFC1A411AE600447C4C /* InjectedBundleFrameHitTest.cpp in Sources */,
</span><span class="cx">                                 7CCE7EFD1A411AE600447C4C /* InjectedBundleInitializationUserDataCallbackWins.cpp in Sources */,
</span><ins>+                                2EFF06D41D8AEDBB0004BB30 /* TestWKWebViewMac.mm in Sources */,
</ins><span class="cx">                                 7C83E0B81D0A64BD00FEBCF3 /* InjectedBundleMakeAllShadowRootsOpen.cpp in Sources */,
</span><span class="cx">                                 7CCE7EC31A411A7E00447C4C /* InspectorBar.mm in Sources */,
</span><span class="cx">                                 7CCE7EDA1A411A8700447C4C /* InstanceMethodSwizzler.mm in Sources */,
</span><span class="lines">@@ -2461,6 +2474,7 @@
</span><span class="cx">                                 7CCE7ED81A411A7E00447C4C /* WillSendSubmitEvent.mm in Sources */,
</span><span class="cx">                                 7CCE7ED91A411A7E00447C4C /* WindowlessWebViewWithMedia.mm in Sources */,
</span><span class="cx">                                 1F83571B1D3FFB2300E3967B /* WKBackForwardList.mm in Sources */,
</span><ins>+                                2EFF06D71D8AF34A0004BB30 /* WKWebViewCandidateTests.mm in Sources */,
</ins><span class="cx">                                 7CCE7F2E1A411B1000447C4C /* WKBrowsingContextGroupTest.mm in Sources */,
</span><span class="cx">                                 7CCE7F2F1A411B1000447C4C /* WKBrowsingContextLoadDelegateTest.mm in Sources */,
</span><span class="cx">                                 7C54A4BE1AA11CCA00380F78 /* WKBundleFileHandle.cpp in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitiosaudioonlyhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/audio-only.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -12,7 +12,7 @@
</span><span class="cx">     function playing() {
</span><span class="cx">         window.clearTimeout(timeout);
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('playing');
</ins><span class="cx">         } catch(e) {
</span><span class="cx">             window.location = 'callback:playing';
</span><span class="cx">         }
</span><span class="lines">@@ -20,7 +20,7 @@
</span><span class="cx"> 
</span><span class="cx">     function notPlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
</ins><span class="cx">         } catch(e) { }
</span><span class="cx">     }
</span><span class="cx">     &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitiosvideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">     function playing() {
</span><span class="cx">         window.clearTimeout(timeout);
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('playing');
</ins><span class="cx">         } catch(e) {
</span><span class="cx">             window.location = 'callback:playing';
</span><span class="cx">         }
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx"> 
</span><span class="cx">     function notPlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
</ins><span class="cx">         } catch(e) { }
</span><span class="cx">     }
</span><span class="cx">    &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKitiosvideowithoutaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit/ios/video-without-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -12,7 +12,7 @@
</span><span class="cx">     function playing() {
</span><span class="cx">         window.clearTimeout(timeout);
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('playing');
</ins><span class="cx">         } catch(e) {
</span><span class="cx">             window.location = 'callback:playing';
</span><span class="cx">         }
</span><span class="lines">@@ -20,7 +20,7 @@
</span><span class="cx"> 
</span><span class="cx">     function notPlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
</ins><span class="cx">         } catch(e) { }
</span><span class="cx">     }
</span><span class="cx">     &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaVideoControlsManagermm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/VideoControlsManager.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -26,11 +26,8 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #import &quot;PlatformUtilities.h&quot;
</span><ins>+#import &quot;TestWKWebViewMac.h&quot;
</ins><span class="cx"> 
</span><del>-#if PLATFORM(MAC)
-#import &lt;Carbon/Carbon.h&gt;
-#endif
-
</del><span class="cx"> #import &lt;WebKit/WKWebViewConfigurationPrivate.h&gt;
</span><span class="cx"> #import &lt;WebKit/WKWebViewPrivate.h&gt;
</span><span class="cx"> #import &lt;wtf/RetainPtr.h&gt;
</span><span class="lines">@@ -43,67 +40,14 @@
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><del>-@interface MessageHandler : NSObject &lt;WKScriptMessageHandler&gt;
</del><ins>+@interface VideoControlsManagerTestWebView : TestWKWebView
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><del>-@implementation MessageHandler {
-    dispatch_block_t _handler;
-    NSString *_message;
-}
-
-- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
-{
-    if (!(self = [super init]))
-        return nil;
-
-    _handler = [handler copy];
-    _message = message;
-
-    return self;
-}
-
-- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
-{
-    if ([(NSString *)[message body] isEqualToString:_message] &amp;&amp; _handler)
-        _handler();
-}
-
-@end
-
-@interface VideoControlsManagerTestWebView : WKWebView
-@end
-
</del><span class="cx"> @implementation VideoControlsManagerTestWebView {
</span><span class="cx">     bool _isDoneQueryingControlledElementID;
</span><span class="cx">     NSString *_controlledElementID;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)mouseDownAtPoint:(NSPoint)point {
-    [self mouseDown:[NSEvent mouseEventWithType:NSEventTypeLeftMouseDown location:NSMakePoint(point.x, point.y) modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:0 pressure:0]];
-}
-
-- (void)performAfterLoading:(dispatch_block_t)actions {
-    MessageHandler *handler = [[MessageHandler alloc] initWithMessage:@&quot;loaded&quot; handler:actions];
-    NSString *onloadScript = @&quot;window.onload = function() { window.webkit.messageHandlers.onloadHandler.postMessage('loaded'); }&quot;;
-    WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
-
-    WKUserContentController* contentController = [[self configuration] userContentController];
-    [contentController addUserScript:script];
-    [contentController addScriptMessageHandler:handler name:@&quot;onloadHandler&quot;];
-}
-
-- (void)callJavascriptFunction:(NSString *)functionName
-{
-    NSString *command = [NSString stringWithFormat:@&quot;%@()&quot;, functionName];
-    [self evaluateJavaScript:command completionHandler:nil];
-}
-
-- (void)loadTestPageNamed:(NSString *)pageName
-{
-    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;]];
-    [self loadRequest:request];
-}
-
</del><span class="cx"> - (void)expectControlsManager:(BOOL)expectControlsManager afterReceivingMessage:(NSString *)message
</span><span class="cx"> {
</span><span class="cx">     __block bool doneWaiting = false;
</span><span class="lines">@@ -131,14 +75,6 @@
</span><span class="cx">         [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
-{
-    RetainPtr&lt;MessageHandler&gt; handler = adoptNS([[MessageHandler alloc] initWithMessage:message handler:action]);
-    WKUserContentController* contentController = [[self configuration] userContentController];
-    [contentController removeScriptMessageHandlerForName:@&quot;playingHandler&quot;];
-    [contentController addScriptMessageHandler:handler.get() name:@&quot;playingHandler&quot;];
-}
-
</del><span class="cx"> - (void)waitForPageToLoadWithAutoplayingVideos:(int)numberOfAutoplayingVideos
</span><span class="cx"> {
</span><span class="cx">     __block int remainingAutoplayedCount = numberOfAutoplayingVideos;
</span><span class="lines">@@ -240,7 +176,7 @@
</span><span class="cx">     [webView loadTestPageNamed:@&quot;large-videos-paused-video-hides-controls&quot;];
</span><span class="cx">     [webView waitForPageToLoadWithAutoplayingVideos:1];
</span><span class="cx"> 
</span><del>-    [webView callJavascriptFunction:@&quot;pauseFirstVideoAndScrollToSecondVideo&quot;];
</del><ins>+    [webView stringByEvaluatingJavaScript:@&quot;pauseFirstVideoAndScrollToSecondVideo()&quot;];
</ins><span class="cx">     [webView expectControlsManager:NO afterReceivingMessage:@&quot;paused&quot;];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -251,7 +187,7 @@
</span><span class="cx">     [webView loadTestPageNamed:@&quot;large-videos-playing-video-keeps-controls&quot;];
</span><span class="cx">     [webView waitForPageToLoadWithAutoplayingVideos:1];
</span><span class="cx"> 
</span><del>-    [webView callJavascriptFunction:@&quot;scrollToSecondVideo&quot;];
</del><ins>+    [webView stringByEvaluatingJavaScript:@&quot;scrollToSecondVideo()&quot;];
</ins><span class="cx">     [webView expectControlsManager:YES afterReceivingMessage:@&quot;scrolled&quot;];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -262,7 +198,7 @@
</span><span class="cx">     [webView loadTestPageNamed:@&quot;large-videos-playing-muted-video-hides-controls&quot;];
</span><span class="cx">     [webView waitForPageToLoadWithAutoplayingVideos:1];
</span><span class="cx"> 
</span><del>-    [webView callJavascriptFunction:@&quot;muteFirstVideoAndScrollToSecondVideo&quot;];
</del><ins>+    [webView stringByEvaluatingJavaScript:@&quot;muteFirstVideoAndScrollToSecondVideo()&quot;];
</ins><span class="cx">     [webView expectControlsManager:NO afterReceivingMessage:@&quot;playing&quot;];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -300,7 +236,7 @@
</span><span class="cx">     [webView loadTestPageNamed:@&quot;large-videos-autoplaying-scroll-to-video&quot;];
</span><span class="cx">     [webView waitForPageToLoadWithAutoplayingVideos:2];
</span><span class="cx"> 
</span><del>-    [webView callJavascriptFunction:@&quot;scrollToSecondView&quot;];
</del><ins>+    [webView stringByEvaluatingJavaScript:@&quot;scrollToSecondView()&quot;];
</ins><span class="cx">     [webView expectControlsManager:YES afterReceivingMessage:@&quot;scrolled&quot;];
</span><span class="cx"> 
</span><span class="cx">     EXPECT_TRUE([[webView controlledElementID] isEqualToString:@&quot;second&quot;]);
</span><span class="lines">@@ -312,7 +248,7 @@
</span><span class="cx"> 
</span><span class="cx">     [webView loadTestPageNamed:@&quot;large-video-playing-scroll-away&quot;];
</span><span class="cx">     [webView waitForPageToLoadWithAutoplayingVideos:1];
</span><del>-    [webView callJavascriptFunction:@&quot;scrollVideoOutOfView&quot;];
</del><ins>+    [webView stringByEvaluatingJavaScript:@&quot;scrollVideoOutOfView()&quot;];
</ins><span class="cx">     [webView expectControlsManager:YES afterReceivingMessage:@&quot;scrolled&quot;];
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2CocoaWKWebViewCandidateTestsmm"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm (0 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/WKWebViewCandidateTests.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -0,0 +1,192 @@
</span><ins>+/*
+ * Copyright (C) 2016 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 &quot;config.h&quot;
+
+#if WK_API_ENABLED &amp;&amp; PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101200
+
+#import &quot;PlatformUtilities.h&quot;
+#import &quot;TestWKWebViewMac.h&quot;
+
+#import &lt;WebKit/WebKitPrivate.h&gt;
+
+static NSString *GetInputValueJSExpression = @&quot;document.querySelector('input').value&quot;;
+static NSString *GetDocumentScrollTopJSExpression = @&quot;document.body.scrollTop&quot;;
+
+@interface TestCandidate : NSTextCheckingResult
+@end
+
+@implementation TestCandidate {
+    NSString *_string;
+    NSRange _range;
+}
+
+- (instancetype)initWithReplacementString:(NSString *)string inRange:(NSRange)range
+{
+    if (self = [super init]) {
+        _string = string;
+        _range = range;
+    }
+    return self;
+}
+
+- (NSString *)replacementString
+{
+    return _string;
+}
+
+- (NSTextCheckingType)resultType
+{
+    return NSTextCheckingTypeReplacement;
+}
+
+- (NSRange)range
+{
+    return _range;
+}
+
+@end
+
+@interface CandidateTestWebView : TestWKWebView
+@property (nonatomic, readonly, getter=isCandidateListVisible) BOOL candidateListVisible;
+@end
+
+@implementation CandidateTestWebView {
+    bool _isDoneWaitingForCandidate;
+    bool _isListeningForCandidateListVisibilityChanges;
+    NSUInteger _candidateListVisibilityChangeCount;
+}
+
+- (void)insertCandidatesAndWaitForResponse:(NSString *)replacementString range:(NSRange)range
+{
+    _isDoneWaitingForCandidate = false;
+    [self _handleAcceptedCandidate:[[TestCandidate alloc] initWithReplacementString:replacementString inRange:range]];
+    TestWebKitAPI::Util::run(&amp;_isDoneWaitingForCandidate);
+}
+
+- (void)_didHandleAcceptedCandidate
+{
+    _isDoneWaitingForCandidate = true;
+}
+
+- (void)expectCandidateListVisibilityUpdates:(NSUInteger)expectedUpdateCount whenPerformingActions:(dispatch_block_t)actions
+{
+    _candidateListVisibilityChangeCount = 0;
+    _isListeningForCandidateListVisibilityChanges = YES;
+
+    actions();
+
+    _isListeningForCandidateListVisibilityChanges = NO;
+    EXPECT_EQ(expectedUpdateCount, _candidateListVisibilityChangeCount);
+}
+
+- (void)_didUpdateCandidateListVisibility:(BOOL)visible
+{
+    if (_candidateListVisible == visible)
+        return;
+
+    _candidateListVisible = visible;
+    if (_isListeningForCandidateListVisibilityChanges)
+        _candidateListVisibilityChangeCount++;
+}
+
+@end
+
+TEST(WKWebViewCandidateTests, SoftSpaceReplacementAfterCandidateInsertionWithoutReplacement)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@&quot;input-field-in-scrollable-document&quot; withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@&quot;focused&quot;];
+    [wkWebView _forceRequestCandidates];
+    [wkWebView insertCandidatesAndWaitForResponse:@&quot;apple &quot; range:NSMakeRange(0, 0)];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;apple &quot;]);
+
+    [wkWebView expectCandidateListVisibilityUpdates:0 whenPerformingActions:^()
+    {
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@&quot;input&quot;];
+    }];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;apple &quot;]);
+    EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+}
+
+TEST(WKWebViewCandidateTests, InsertCharactersAfterCandidateInsertionWithSoftSpace)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@&quot;input-field-in-scrollable-document&quot; withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@&quot;focused&quot;];
+    [wkWebView _forceRequestCandidates];
+    [wkWebView insertCandidatesAndWaitForResponse:@&quot;foo &quot; range:NSMakeRange(0, 0)];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;foo &quot;]);
+
+    [wkWebView typeCharacter:'a'];
+    [wkWebView waitForMessage:@&quot;input&quot;];
+
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;foo a&quot;]);
+}
+
+TEST(WKWebViewCandidateTests, InsertCandidateFromPartiallyTypedPhraseWithSoftSpace)
+{
+    CandidateTestWebView *wkWebView = [[CandidateTestWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+
+    NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@&quot;input-field-in-scrollable-document&quot; withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;];
+    [wkWebView loadRequest:[NSURLRequest requestWithURL:contentURL]];
+
+    [wkWebView waitForMessage:@&quot;focused&quot;];
+    [wkWebView _forceRequestCandidates];
+
+    NSString *initialValue = @&quot;hel&quot;;
+    for (uint64_t i = 0; i &lt; initialValue.length; ++i) {
+        [wkWebView typeCharacter:[initialValue characterAtIndex:i]];
+        [wkWebView waitForMessage:@&quot;input&quot;];
+    }
+
+    [wkWebView insertCandidatesAndWaitForResponse:@&quot;hello &quot; range:NSMakeRange(0, 3)];
+    EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;hello &quot;]);
+
+    [wkWebView expectCandidateListVisibilityUpdates:0 whenPerformingActions:^()
+    {
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@&quot;input&quot;];
+        EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;hello &quot;]);
+        EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+
+        [wkWebView typeCharacter:' '];
+        [wkWebView waitForMessage:@&quot;input&quot;];
+        EXPECT_TRUE([[wkWebView stringByEvaluatingJavaScript:GetInputValueJSExpression] isEqualToString:@&quot;hello  &quot;]);
+        EXPECT_EQ([[wkWebView stringByEvaluatingJavaScript:GetDocumentScrollTopJSExpression] doubleValue], 0);
+    }];
+}
+
+#endif /* WK_API_ENABLED &amp;&amp; PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101200 */
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoaautoplayingvideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/autoplaying-video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -12,7 +12,7 @@
</span><span class="cx">         // Wait until the next runloop to allow media controls to update.
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;paused&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;paused&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -20,7 +20,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoachangevideosourceonclickhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-click.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -12,7 +12,7 @@
</span><span class="cx">             video.play();
</span><span class="cx">             setTimeout(function() {
</span><span class="cx">                 try {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;changed&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;changed&quot;);
</ins><span class="cx">                 } catch(e) {
</span><span class="cx">                 }
</span><span class="cx">             });
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx">         function handlePlaying() {
</span><span class="cx">             setTimeout(function() {
</span><span class="cx">                 try {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">                 } catch(e) {
</span><span class="cx">                 }
</span><span class="cx">             }, 0);
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoachangevideosourceonendhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/change-video-source-on-end.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">             video.play();
</span><span class="cx">             setTimeout(function() {
</span><span class="cx">                 try {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;changed&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;changed&quot;);
</ins><span class="cx">                 } catch(e) {
</span><span class="cx">                 }
</span><span class="cx">             });
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoafullsizeautoplayingvideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/full-size-autoplaying-video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx">     function finishTest() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;playing&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;playing&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoainputfieldinscrollabledocumenthtml"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html (0 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/input-field-in-scrollable-document.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+&lt;html&gt;
+
+&lt;head&gt;
+    &lt;style&gt;
+        body {
+            margin: 0;
+        }
+
+        input {
+            width: 100%;
+            height: 400px;
+            margin-bottom: 5000px;
+        }
+    &lt;/style&gt;
+    &lt;script type=&quot;text/javascript&quot;&gt;
+        function loaded() {
+            var input = document.querySelector(&quot;input&quot;);
+            input.setSelectionRange(0, 0);
+            input.focus();
+        }
+
+        function focused() {
+            setTimeout(() =&gt; window.webkit.messageHandlers.testHandler.postMessage(&quot;focused&quot;), 0);
+        }
+
+        function input() {
+            setTimeout(() =&gt; window.webkit.messageHandlers.testHandler.postMessage(&quot;input&quot;), 0);
+        }
+    &lt;/script&gt;
+&lt;/head&gt;
+
+&lt;body onload=loaded()&gt;
+    &lt;input onfocus=focused() oninput=input()&gt;&lt;/input&gt;
+&lt;/body&gt;
+
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideohidescontrolsafterseektoendhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-hides-controls-after-seek-to-end.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -7,7 +7,7 @@
</span><span class="cx">         // The media controls should be updated on the next runloop.
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;ended&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;ended&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideomutesonplayinghtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-mutes-onplaying.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> &lt;script&gt;
</span><span class="cx">     function handlePlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage(&quot;playing&quot;);
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage(&quot;playing&quot;);
</ins><span class="cx">         } catch(e) {
</span><span class="cx">         }
</span><span class="cx">         document.querySelector(&quot;video&quot;).muted = true;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideooffscreenhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-offscreen.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx">             document.querySelector(&quot;video&quot;).classList.add(&quot;offscreen&quot;);
</span><span class="cx">             setTimeout(function() {
</span><span class="cx">                 try {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;moved&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;moved&quot;);
</ins><span class="cx">                 } catch(e) {
</span><span class="cx">                 }
</span><span class="cx">             }, 0);
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoplayingscrollawayhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-playing-scroll-away.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">             function scrollVideoOutOfView() {
</span><span class="cx">                 document.querySelector(&quot;div&quot;).scrollIntoView();
</span><span class="cx">                 setTimeout(function() {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;scrolled&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;scrolled&quot;);
</ins><span class="cx">                 }, 0);
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx">             function beganAutoplaying() {
</span><span class="cx">                 setTimeout(function() {
</span><span class="cx">                     try {
</span><del>-                        window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                        window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">                     } catch(e) {
</span><span class="cx">                     }
</span><span class="cx">                 }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoseekafterendinghtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-after-ending.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -6,7 +6,7 @@
</span><span class="cx">             document.querySelector(&quot;#test-video&quot;).currentTime = 0;
</span><span class="cx">             // The media controls should be updated on the next runloop.
</span><span class="cx">             setTimeout(function() {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;ended&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;ended&quot;);
</ins><span class="cx">             }, 0);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoseektobeginningandplayafterendinghtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-seek-to-beginning-and-play-after-ending.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -8,7 +8,7 @@
</span><span class="cx">             video.play();
</span><span class="cx">             // The media controls should be updated on the next runloop.
</span><span class="cx">             setTimeout(function() {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;replaying&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;replaying&quot;);
</ins><span class="cx">             }, 0);
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">         window.clearTimeout(timeout);
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage('playing');
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage('playing');
</ins><span class="cx">             } catch(e) {
</span><span class="cx">                 window.location = 'callback:playing';
</span><span class="cx">             }
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx"> 
</span><span class="cx">     function notPlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
</ins><span class="cx">         } catch(e) { }
</span><span class="cx">     }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideowithoutaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-video-without-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -13,7 +13,7 @@
</span><span class="cx">     function playing() {
</span><span class="cx">         window.clearTimeout(timeout);
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('playing');
</ins><span class="cx">         } catch(e) {
</span><span class="cx">             window.location = 'callback:playing';
</span><span class="cx">         }
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx"> 
</span><span class="cx">     function notPlaying() {
</span><span class="cx">         try {
</span><del>-            window.webkit.messageHandlers.playingHandler.postMessage('not playing');
</del><ins>+            window.webkit.messageHandlers.testHandler.postMessage('not playing');
</ins><span class="cx">         } catch(e) { }
</span><span class="cx">     }
</span><span class="cx"> &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosautoplayingclicktopausehtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-click-to-pause.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx">             function handleFirstPause() {
</span><span class="cx">                 setTimeout(function() {
</span><span class="cx">                     try {
</span><del>-                        window.webkit.messageHandlers.playingHandler.postMessage(&quot;paused&quot;);
</del><ins>+                        window.webkit.messageHandlers.testHandler.postMessage(&quot;paused&quot;);
</ins><span class="cx">                     } catch(e) { }
</span><span class="cx">                 }, 0);
</span><span class="cx">             }
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx">             function handleSecondPause() {
</span><span class="cx">                 setTimeout(function() {
</span><span class="cx">                     try {
</span><del>-                        window.webkit.messageHandlers.playingHandler.postMessage(&quot;paused&quot;);
</del><ins>+                        window.webkit.messageHandlers.testHandler.postMessage(&quot;paused&quot;);
</ins><span class="cx">                     } catch(e) { }
</span><span class="cx">                 }, 0);
</span><span class="cx">             }
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">             function beganAutoplaying() {
</span><span class="cx">                 setTimeout(function() {
</span><span class="cx">                     try {
</span><del>-                        window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                        window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">                     } catch(e) {
</span><span class="cx">                     }
</span><span class="cx">                 }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosautoplayingscrolltovideohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-autoplaying-scroll-to-video.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,13 +14,13 @@
</span><span class="cx">             function scrollToSecondView() {
</span><span class="cx">                 document.querySelector(&quot;#second&quot;).scrollIntoView();
</span><span class="cx">                 setTimeout(function() {
</span><del>-                    window.webkit.messageHandlers.playingHandler.postMessage(&quot;scrolled&quot;);
</del><ins>+                    window.webkit.messageHandlers.testHandler.postMessage(&quot;scrolled&quot;);
</ins><span class="cx">                 }, 0);
</span><span class="cx">             }
</span><span class="cx">             function beganAutoplaying() {
</span><span class="cx">                 setTimeout(function() {
</span><span class="cx">                     try {
</span><del>-                        window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                        window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">                     } catch(e) {
</span><span class="cx">                     }
</span><span class="cx">                 }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideospausedvideohidescontrolshtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-paused-video-hides-controls.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -17,7 +17,7 @@
</span><span class="cx">     function handlePaused() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;paused&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;paused&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosplayingmutedvideohidescontrolshtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-muted-video-hides-controls.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -15,7 +15,7 @@
</span><span class="cx">         document.querySelector(&quot;#bar&quot;).scrollIntoView();
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;playing&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;playing&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -22,7 +22,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideosplayingvideokeepscontrolshtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-playing-video-keeps-controls.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">         document.querySelector(&quot;#bar&quot;).scrollIntoView();
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;scrolled&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;scrolled&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoalargevideoswithaudioautoplayhtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/large-videos-with-audio-autoplay.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx">     function beganAutoplaying() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;autoplayed&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;autoplayed&quot;);
</ins><span class="cx">             } catch(e) {
</span><span class="cx">             }
</span><span class="cx">         }, 0)
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoaskinnyautoplayingvideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/skinny-autoplaying-video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx">     function finishTest() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;playing&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;playing&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoawideautoplayingvideowithaudiohtml"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html (206032 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html        2016-09-16 18:04:54 UTC (rev 206032)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/wide-autoplaying-video-with-audio.html        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx">     function finishTest() {
</span><span class="cx">         setTimeout(function() {
</span><span class="cx">             try {
</span><del>-                window.webkit.messageHandlers.playingHandler.postMessage(&quot;playing&quot;);
</del><ins>+                window.webkit.messageHandlers.testHandler.postMessage(&quot;playing&quot;);
</ins><span class="cx">             } catch(e) { }
</span><span class="cx">         }, 0);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPImacTestWKWebViewMachfromrev206032trunkSourceWebKit2SharedmacNativeWebKeyboardEventMacmm"></a>
<div class="copfile"><h4>Copied: trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h (from rev 206032, trunk/Source/WebKit2/Shared/mac/NativeWebKeyboardEventMac.mm) (0 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.h        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef TestWKWebViewMac_h
+#define TestWKWebViewMac_h
+
+#import &lt;WebKit/WebKit.h&gt;
+
+#if WK_API_ENABLED &amp;&amp; PLATFORM(MAC)
+
+@interface TestMessageHandler : NSObject &lt;WKScriptMessageHandler&gt;
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler;
+@end
+
+@interface TestWKWebView : WKWebView
+- (void)mouseDownAtPoint:(NSPoint)point;
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action;
+- (void)loadTestPageNamed:(NSString *)pageName;
+- (void)typeCharacter:(char)character;
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script;
+- (void)waitForMessage:(NSString *)message;
+- (void)performAfterLoading:(dispatch_block_t)actions;
+@end
+
+#endif /* WK_API_ENABLED &amp;&amp; PLATFORM(MAC) */
+
+#endif /* TestWKWebViewMac_h */
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPImacTestWKWebViewMacmm"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm (0 => 206033)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/mac/TestWKWebViewMac.mm        2016-09-16 18:14:04 UTC (rev 206033)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+/*
+ * Copyright (C) 2016 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 &quot;config.h&quot;
+#import &quot;TestWKWebViewMac.h&quot;
+
+#if WK_API_ENABLED &amp;&amp; PLATFORM(MAC)
+
+#import &quot;Utilities.h&quot;
+
+#import &lt;AppKit/AppKit.h&gt;
+#import &lt;Carbon/Carbon.h&gt;
+#import &lt;WebKit/WebKitPrivate.h&gt;
+#import &lt;wtf/RetainPtr.h&gt;
+
+@implementation TestMessageHandler {
+    dispatch_block_t _handler;
+    NSString *_message;
+}
+
+- (instancetype)initWithMessage:(NSString *)message handler:(dispatch_block_t)handler
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _handler = [handler copy];
+    _message = message;
+
+    return self;
+}
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
+{
+    if ([(NSString *)[message body] isEqualToString:_message] &amp;&amp; _handler)
+        _handler();
+}
+
+@end
+
+@implementation TestWKWebView
+
+- (void)mouseDownAtPoint:(NSPoint)point
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101200
+    NSEventType mouseEventType = NSEventTypeLeftMouseDown;
+#else
+    NSEventType mouseEventType = NSLeftMouseDown;
+#endif
+    [self mouseDown:[NSEvent mouseEventWithType:mouseEventType location:NSMakePoint(point.x, point.y) modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:[NSGraphicsContext currentContext] eventNumber:0 clickCount:0 pressure:0]];
+}
+
+- (void)performAfterReceivingMessage:(NSString *)message action:(dispatch_block_t)action
+{
+    RetainPtr&lt;TestMessageHandler&gt; handler = adoptNS([[TestMessageHandler alloc] initWithMessage:message handler:action]);
+    WKUserContentController* contentController = [[self configuration] userContentController];
+    [contentController removeScriptMessageHandlerForName:@&quot;testHandler&quot;];
+    [contentController addScriptMessageHandler:handler.get() name:@&quot;testHandler&quot;];
+}
+
+- (void)loadTestPageNamed:(NSString *)pageName
+{
+    NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:pageName withExtension:@&quot;html&quot; subdirectory:@&quot;TestWebKitAPI.resources&quot;]];
+    [self loadRequest:request];
+}
+
+- (void)typeCharacter:(char)character {
+    NSString *characterAsString = [NSString stringWithFormat:@&quot;%c&quot; , character];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 101200
+    NSEventType keyDownEventType = NSEventTypeKeyDown;
+    NSEventType keyUpEventType = NSEventTypeKeyUp;
+#else
+    NSEventType keyDownEventType = NSKeyDown;
+    NSEventType keyUpEventType = NSKeyUp;
+#endif
+    [self keyDown:[NSEvent keyEventWithType:keyDownEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+    [self keyUp:[NSEvent keyEventWithType:keyUpEventType location:NSZeroPoint modifierFlags:0 timestamp:GetCurrentEventTime() windowNumber:0 context:nil characters:characterAsString charactersIgnoringModifiers:characterAsString isARepeat:NO keyCode:character]];
+}
+
+- (NSString *)stringByEvaluatingJavaScript:(NSString *)script
+{
+    __block bool isWaitingForJavaScript = false;
+    __block NSString *evalResult = nil;
+    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error)
+    {
+        evalResult = [NSString stringWithFormat:@&quot;%@&quot;, result];
+        isWaitingForJavaScript = true;
+        EXPECT_TRUE(!error);
+    }];
+
+    TestWebKitAPI::Util::run(&amp;isWaitingForJavaScript);
+    return evalResult;
+}
+
+- (void)waitForMessage:(NSString *)message
+{
+    __block bool isDoneWaiting = false;
+    [self performAfterReceivingMessage:message action:^()
+    {
+        isDoneWaiting = true;
+    }];
+    TestWebKitAPI::Util::run(&amp;isDoneWaiting);
+}
+
+- (void)performAfterLoading:(dispatch_block_t)actions {
+    TestMessageHandler *handler = [[TestMessageHandler alloc] initWithMessage:@&quot;loaded&quot; handler:actions];
+    NSString *onloadScript = @&quot;window.onload = () =&gt; window.webkit.messageHandlers.onloadHandler.postMessage('loaded')&quot;;
+    WKUserScript *script = [[WKUserScript alloc] initWithSource:onloadScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
+
+    WKUserContentController* contentController = [[self configuration] userContentController];
+    [contentController addUserScript:script];
+    [contentController addScriptMessageHandler:handler name:@&quot;onloadHandler&quot;];
+}
+
+@end
+
+#endif /* WK_API_ENABLED &amp;&amp; PLATFORM(MAC) */
</ins></span></pre>
</div>
</div>

</body>
</html>