<!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>[191791] trunk/Source/WebKit2</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/191791">191791</a></dd>
<dt>Author</dt> <dd>timothy_horton@apple.com</dd>
<dt>Date</dt> <dd>2015-10-30 10:02:36 -0700 (Fri, 30 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>WKView being inside WKWebView leads to weird API issues
https://bugs.webkit.org/show_bug.cgi?id=150174

Reviewed by Darin Adler.

* UIProcess/API/mac/WKView.mm:
(-[WKView doCommandBySelector:]):
(-[WKView insertText:]):
(-[WKView insertText:replacementRange:]):
(-[WKView inputContext]):
(-[WKView performKeyEquivalent:]):
(-[WKView keyUp:]):
(-[WKView keyDown:]):
(-[WKView flagsChanged:]):
(-[WKView setMarkedText:selectedRange:replacementRange:]):
(-[WKView unmarkText]):
(-[WKView selectedRange]):
(-[WKView hasMarkedText]):
(-[WKView markedRange]):
(-[WKView attributedSubstringForProposedRange:actualRange:]):
(-[WKView characterIndexForPoint:]):
(-[WKView firstRectForCharacterRange:actualRange:]):
(-[WKView selectedRangeWithCompletionHandler:]):
(-[WKView markedRangeWithCompletionHandler:]):
(-[WKView hasMarkedTextWithCompletionHandler:]):
(-[WKView attributedSubstringForProposedRange:completionHandler:]):
(-[WKView firstRectForCharacterRange:completionHandler:]):
(-[WKView characterIndexForPoint:completionHandler:]):
(-[WKView _superPerformKeyEquivalent:]):
(-[WKView _superKeyDown:]):
(extractUnderlines): Deleted.
(-[WKView _collectKeyboardLayoutCommandsForEvent:to:]): Deleted.
(-[WKView _interpretKeyEvent:completionHandler:]): Deleted.
(-[WKView NO_RETURN_DUE_TO_ASSERT]): Deleted.
(-[WKView _interpretKeyEvent:savingCommandsTo:]): Deleted.
(-[WKView _executeSavedKeypressCommands]): Deleted.
(-[WKView _doneWithKeyEvent:eventWasHandled:]): Deleted.
* UIProcess/API/mac/WKViewInternal.h:
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::doneWithKeyEvent):
(WebKit::extractUnderlines):
(WebKit::WebViewImpl::collectKeyboardLayoutCommandsForEvent):
(WebKit::WebViewImpl::interpretKeyEvent):
(WebKit::WebViewImpl::doCommandBySelector):
(WebKit::WebViewImpl::insertText):
(WebKit::WebViewImpl::selectedRangeWithCompletionHandler):
(WebKit::WebViewImpl::markedRangeWithCompletionHandler):
(WebKit::WebViewImpl::hasMarkedTextWithCompletionHandler):
(WebKit::WebViewImpl::attributedSubstringForProposedRange):
(WebKit::WebViewImpl::firstRectForCharacterRange):
(WebKit::WebViewImpl::characterIndexForPoint):
(WebKit::WebViewImpl::inputContext):
(WebKit::WebViewImpl::unmarkText):
(WebKit::WebViewImpl::setMarkedText):
(WebKit::WebViewImpl::selectedRange):
(WebKit::WebViewImpl::hasMarkedText):
(WebKit::WebViewImpl::markedRange):
(WebKit::WebViewImpl::performKeyEquivalent):
(WebKit::WebViewImpl::keyUp):
(WebKit::WebViewImpl::keyDown):
(WebKit::WebViewImpl::flagsChanged):
(WebKit::WebViewImpl::executeSavedKeypressCommands):
* UIProcess/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::doneWithKeyEvent):
Move NSTextInputClient implementation.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPImacWKViewmm">trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPImacWKViewInternalh">trunk/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h</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="#trunkSourceWebKit2UIProcessmacPageClientImplmm">trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/ChangeLog        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -1,3 +1,72 @@
</span><ins>+2015-10-30  Tim Horton  &lt;timothy_horton@apple.com&gt;
+
+        WKView being inside WKWebView leads to weird API issues
+        https://bugs.webkit.org/show_bug.cgi?id=150174
+
+        Reviewed by Darin Adler.
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView doCommandBySelector:]):
+        (-[WKView insertText:]):
+        (-[WKView insertText:replacementRange:]):
+        (-[WKView inputContext]):
+        (-[WKView performKeyEquivalent:]):
+        (-[WKView keyUp:]):
+        (-[WKView keyDown:]):
+        (-[WKView flagsChanged:]):
+        (-[WKView setMarkedText:selectedRange:replacementRange:]):
+        (-[WKView unmarkText]):
+        (-[WKView selectedRange]):
+        (-[WKView hasMarkedText]):
+        (-[WKView markedRange]):
+        (-[WKView attributedSubstringForProposedRange:actualRange:]):
+        (-[WKView characterIndexForPoint:]):
+        (-[WKView firstRectForCharacterRange:actualRange:]):
+        (-[WKView selectedRangeWithCompletionHandler:]):
+        (-[WKView markedRangeWithCompletionHandler:]):
+        (-[WKView hasMarkedTextWithCompletionHandler:]):
+        (-[WKView attributedSubstringForProposedRange:completionHandler:]):
+        (-[WKView firstRectForCharacterRange:completionHandler:]):
+        (-[WKView characterIndexForPoint:completionHandler:]):
+        (-[WKView _superPerformKeyEquivalent:]):
+        (-[WKView _superKeyDown:]):
+        (extractUnderlines): Deleted.
+        (-[WKView _collectKeyboardLayoutCommandsForEvent:to:]): Deleted.
+        (-[WKView _interpretKeyEvent:completionHandler:]): Deleted.
+        (-[WKView NO_RETURN_DUE_TO_ASSERT]): Deleted.
+        (-[WKView _interpretKeyEvent:savingCommandsTo:]): Deleted.
+        (-[WKView _executeSavedKeypressCommands]): Deleted.
+        (-[WKView _doneWithKeyEvent:eventWasHandled:]): Deleted.
+        * UIProcess/API/mac/WKViewInternal.h:
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::doneWithKeyEvent):
+        (WebKit::extractUnderlines):
+        (WebKit::WebViewImpl::collectKeyboardLayoutCommandsForEvent):
+        (WebKit::WebViewImpl::interpretKeyEvent):
+        (WebKit::WebViewImpl::doCommandBySelector):
+        (WebKit::WebViewImpl::insertText):
+        (WebKit::WebViewImpl::selectedRangeWithCompletionHandler):
+        (WebKit::WebViewImpl::markedRangeWithCompletionHandler):
+        (WebKit::WebViewImpl::hasMarkedTextWithCompletionHandler):
+        (WebKit::WebViewImpl::attributedSubstringForProposedRange):
+        (WebKit::WebViewImpl::firstRectForCharacterRange):
+        (WebKit::WebViewImpl::characterIndexForPoint):
+        (WebKit::WebViewImpl::inputContext):
+        (WebKit::WebViewImpl::unmarkText):
+        (WebKit::WebViewImpl::setMarkedText):
+        (WebKit::WebViewImpl::selectedRange):
+        (WebKit::WebViewImpl::hasMarkedText):
+        (WebKit::WebViewImpl::markedRange):
+        (WebKit::WebViewImpl::performKeyEquivalent):
+        (WebKit::WebViewImpl::keyUp):
+        (WebKit::WebViewImpl::keyDown):
+        (WebKit::WebViewImpl::flagsChanged):
+        (WebKit::WebViewImpl::executeSavedKeypressCommands):
+        * UIProcess/mac/PageClientImpl.mm:
+        (WebKit::PageClientImpl::doneWithKeyEvent):
+        Move NSTextInputClient implementation.
+
</ins><span class="cx"> 2015-10-30  Carlos Garcia Campos  &lt;cgarcia@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Move the socket polling off the WorkQueue
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPImacWKViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKView.mm        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -110,41 +110,14 @@
</span><span class="cx"> #import &quot;WKBrowsingContextGroupPrivate.h&quot;
</span><span class="cx"> #import &quot;WKProcessGroupPrivate.h&quot;
</span><span class="cx"> 
</span><del>-#if USE(ASYNC_NSTEXTINPUTCLIENT)
-@interface NSTextInputContext (WKNSTextInputContextDetails)
-- (void)handleEvent:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
-- (void)handleEventByInputMethod:(NSEvent *)theEvent completionHandler:(void(^)(BOOL handled))completionHandler;
-- (BOOL)handleEventByKeyboardLayout:(NSEvent *)theEvent;
-@end
-#endif
-
</del><span class="cx"> using namespace WebKit;
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><del>-#if !USE(ASYNC_NSTEXTINPUTCLIENT)
-struct WKViewInterpretKeyEventsParameters {
-    bool eventInterpretationHadSideEffects;
-    bool consumedByIM;
-    bool executingSavedKeypressCommands;
-    Vector&lt;KeypressCommand&gt;* commands;
-};
-#endif
-
</del><span class="cx"> @interface WKViewData : NSObject {
</span><span class="cx"> @public
</span><span class="cx">     std::unique_ptr&lt;PageClientImpl&gt; _pageClient;
</span><span class="cx">     RefPtr&lt;WebPageProxy&gt; _page;
</span><span class="cx">     std::unique_ptr&lt;WebViewImpl&gt; _impl;
</span><del>-
-    // We keep here the event when resending it to
-    // the application to distinguish the case of a new event from one 
-    // that has been already sent to WebCore.
-    RetainPtr&lt;NSEvent&gt; _keyDownEventBeingResent;
-#if USE(ASYNC_NSTEXTINPUTCLIENT)
-    Vector&lt;KeypressCommand&gt;* _collectedKeypressCommands;
-#else
-    WKViewInterpretKeyEventsParameters* _interpretKeyEventsParameters;
-#endif
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="lines">@@ -758,932 +731,116 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void extractUnderlines(NSAttributedString *string, Vector&lt;CompositionUnderline&gt;&amp; result)
-{
-    int length = [[string string] length];
-    
-    int i = 0;
-    while (i &lt; length) {
-        NSRange range;
-        NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&amp;range inRange:NSMakeRange(i, length - i)];
-        
-        if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
-            Color color = Color::black;
-            if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
-                color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
-            result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] &gt; 1));
-        }
-        
-        i = range.location + range.length;
-    }
-}
-
-#if USE(ASYNC_NSTEXTINPUTCLIENT)
-
-- (void)_collectKeyboardLayoutCommandsForEvent:(NSEvent *)event to:(Vector&lt;KeypressCommand&gt;&amp;)commands
-{
-    if ([event type] != NSKeyDown)
-        return;
-
-    ASSERT(!_data-&gt;_collectedKeypressCommands);
-    _data-&gt;_collectedKeypressCommands = &amp;commands;
-
-    if (NSTextInputContext *context = [self inputContext])
-        [context handleEventByKeyboardLayout:event];
-    else
-        [self interpretKeyEvents:[NSArray arrayWithObject:event]];
-
-    _data-&gt;_collectedKeypressCommands = nullptr;
-}
-
-- (void)_interpretKeyEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled, const Vector&lt;KeypressCommand&gt;&amp; commands))completionHandler
-{
-    // For regular Web content, input methods run before passing a keydown to DOM, but plug-ins get an opportunity to handle the event first.
-    // There is no need to collect commands, as the plug-in cannot execute them.
-    if (_data-&gt;_impl-&gt;pluginComplexTextInputIdentifier()) {
-        completionHandler(NO, Vector&lt;KeypressCommand&gt;());
-        return;
-    }
-
-    if (![self inputContext]) {
-        Vector&lt;KeypressCommand&gt; commands;
-        [self _collectKeyboardLayoutCommandsForEvent:event to:commands];
-        completionHandler(NO, commands);
-        return;
-    }
-
-    LOG(TextInput, &quot;-&gt; handleEventByInputMethod:%p %@&quot;, event, event);
-    [[self inputContext] handleEventByInputMethod:event completionHandler:^(BOOL handled) {
-        
-        LOG(TextInput, &quot;... handleEventByInputMethod%s handled&quot;, handled ? &quot;&quot; : &quot; not&quot;);
-        if (handled) {
-            completionHandler(YES, Vector&lt;KeypressCommand&gt;());
-            return;
-        }
-
-        Vector&lt;KeypressCommand&gt; commands;
-        [self _collectKeyboardLayoutCommandsForEvent:event to:commands];
-        completionHandler(NO, commands);
-    }];
-}
-
</del><span class="cx"> - (void)doCommandBySelector:(SEL)selector
</span><span class="cx"> {
</span><del>-    LOG(TextInput, &quot;doCommandBySelector:\&quot;%s\&quot;&quot;, sel_getName(selector));
-
-    Vector&lt;KeypressCommand&gt;* keypressCommands = _data-&gt;_collectedKeypressCommands;
-
-    if (keypressCommands) {
-        KeypressCommand command(NSStringFromSelector(selector));
-        keypressCommands-&gt;append(command);
-        LOG(TextInput, &quot;...stored&quot;);
-        _data-&gt;_page-&gt;registerKeypressCommandName(command.commandName);
-    } else {
-        // FIXME: Send the command to Editor synchronously and only send it along the
-        // responder chain if it's a selector that does not correspond to an editing command.
-        [super doCommandBySelector:selector];
-    }
</del><ins>+    _data-&gt;_impl-&gt;doCommandBySelector(selector);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)insertText:(id)string
</span><span class="cx"> {
</span><del>-    // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
-    // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
-    // command ensures that a keypress event is dispatched as appropriate.
-    [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)];
</del><ins>+    _data-&gt;_impl-&gt;insertText(string);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
</span><span class="cx"> {
</span><del>-    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
-    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
-
-    if (replacementRange.location != NSNotFound)
-        LOG(TextInput, &quot;insertText:\&quot;%@\&quot; replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
-    else
-        LOG(TextInput, &quot;insertText:\&quot;%@\&quot;&quot;, isAttributedString ? [string string] : string);
-
-    NSString *text;
-    Vector&lt;TextAlternativeWithRange&gt; dictationAlternatives;
-
-    bool registerUndoGroup = false;
-    if (isAttributedString) {
-#if USE(DICTATION_ALTERNATIVES)
-        collectDictationTextAlternatives(string, dictationAlternatives);
-#endif
-#if USE(INSERTION_UNDO_GROUPING)
-        registerUndoGroup = shouldRegisterInsertionUndoGroup(string);
-#endif
-        // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
-        text = [string string];
-    } else
-        text = string;
-
-    // insertText can be called for several reasons:
-    // - If it's from normal key event processing (including key bindings), we save the action to perform it later.
-    // - If it's from an input method, then we should insert the text now.
-    // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
-    // then we also execute it immediately, as there will be no other chance.
-    Vector&lt;KeypressCommand&gt;* keypressCommands = _data-&gt;_collectedKeypressCommands;
-    if (keypressCommands) {
-        ASSERT(replacementRange.location == NSNotFound);
-        KeypressCommand command(&quot;insertText:&quot;, text);
-        keypressCommands-&gt;append(command);
-        LOG(TextInput, &quot;...stored&quot;);
-        _data-&gt;_page-&gt;registerKeypressCommandName(command.commandName);
-        return;
-    }
-
-    String eventText = text;
-    eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
-    if (!dictationAlternatives.isEmpty())
-        _data-&gt;_page-&gt;insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
-    else
-        _data-&gt;_page-&gt;insertTextAsync(eventText, replacementRange, registerUndoGroup);
</del><ins>+    _data-&gt;_impl-&gt;insertText(string, replacementRange);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;selectedRange&quot;);
-    _data-&gt;_page-&gt;getSelectedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...selectedRange failed.&quot;);
-            completionHandlerBlock(NSMakeRange(NSNotFound, 0));
-            return;
-        }
-        NSRange result = editingRangeResult;
-        if (result.location == NSNotFound)
-            LOG(TextInput, &quot;    -&gt; selectedRange returned (NSNotFound, %llu)&quot;, result.length);
-        else
-            LOG(TextInput, &quot;    -&gt; selectedRange returned (%llu, %llu)&quot;, result.location, result.length);
-        completionHandlerBlock(result);
-    });
-}
-
-- (void)markedRangeWithCompletionHandler:(void(^)(NSRange markedRange))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;markedRange&quot;);
-    _data-&gt;_page-&gt;getMarkedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...markedRange failed.&quot;);
-            completionHandlerBlock(NSMakeRange(NSNotFound, 0));
-            return;
-        }
-        NSRange result = editingRangeResult;
-        if (result.location == NSNotFound)
-            LOG(TextInput, &quot;    -&gt; markedRange returned (NSNotFound, %llu)&quot;, result.length);
-        else
-            LOG(TextInput, &quot;    -&gt; markedRange returned (%llu, %llu)&quot;, result.location, result.length);
-        completionHandlerBlock(result);
-    });
-}
-
-- (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;hasMarkedText&quot;);
-    _data-&gt;_page-&gt;getMarkedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(BOOL) = (void (^)(BOOL))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...hasMarkedText failed.&quot;);
-            completionHandlerBlock(NO);
-            return;
-        }
-        BOOL hasMarkedText = editingRangeResult.location != notFound;
-        LOG(TextInput, &quot;    -&gt; hasMarkedText returned %u&quot;, hasMarkedText);
-        completionHandlerBlock(hasMarkedText);
-    });
-}
-
-- (void)attributedSubstringForProposedRange:(NSRange)nsRange completionHandler:(void(^)(NSAttributedString *attrString, NSRange actualRange))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u)&quot;, nsRange.location, nsRange.length);
-    _data-&gt;_page-&gt;attributedSubstringForCharacterRangeAsync(nsRange, [completionHandler](const AttributedString&amp; string, const EditingRange&amp; actualRange, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(NSAttributedString *, NSRange) = (void (^)(NSAttributedString *, NSRange))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...attributedSubstringFromRange failed.&quot;);
-            completionHandlerBlock(0, NSMakeRange(NSNotFound, 0));
-            return;
-        }
-        LOG(TextInput, &quot;    -&gt; attributedSubstringFromRange returned %@&quot;, [string.string.get() string]);
-        completionHandlerBlock([[string.string.get() retain] autorelease], actualRange);
-    });
-}
-
-- (void)firstRectForCharacterRange:(NSRange)theRange completionHandler:(void(^)(NSRect firstRect, NSRange actualRange))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;firstRectForCharacterRange:(%u, %u)&quot;, theRange.location, theRange.length);
-
-    // Just to match NSTextView's behavior. Regression tests cannot detect this;
-    // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
-    // (type something; try ranges (1, -1) and (2, -1).
-    if ((theRange.location + theRange.length &lt; theRange.location) &amp;&amp; (theRange.location + theRange.length != 0))
-        theRange.length = 0;
-
-    if (theRange.location == NSNotFound) {
-        LOG(TextInput, &quot;    -&gt; NSZeroRect&quot;);
-        completionHandlerPtr(NSZeroRect, theRange);
-        return;
-    }
-
-    _data-&gt;_page-&gt;firstRectForCharacterRangeAsync(theRange, [self, completionHandler](const IntRect&amp; rect, const EditingRange&amp; actualRange, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(NSRect, NSRange) = (void (^)(NSRect, NSRange))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...firstRectForCharacterRange failed.&quot;);
-            completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
-            return;
-        }
-
-        NSRect resultRect = [self convertRect:rect toView:nil];
-        resultRect = [self.window convertRectToScreen:resultRect];
-
-        LOG(TextInput, &quot;    -&gt; firstRectForCharacterRange returned (%f, %f, %f, %f)&quot;, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
-        completionHandlerBlock(resultRect, actualRange);
-    });
-}
-
-- (void)characterIndexForPoint:(NSPoint)thePoint completionHandler:(void(^)(NSUInteger))completionHandlerPtr
-{
-    RetainPtr&lt;id&gt; completionHandler = adoptNS([completionHandlerPtr copy]);
-
-    LOG(TextInput, &quot;characterIndexForPoint:(%f, %f)&quot;, thePoint.x, thePoint.y);
-
-    NSWindow *window = [self window];
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
-    if (window)
-        thePoint = [window convertScreenToBase:thePoint];
-#pragma clang diagnostic pop
-    thePoint = [self convertPoint:thePoint fromView:nil];  // the point is relative to the main frame
-
-    _data-&gt;_page-&gt;characterIndexForPointAsync(IntPoint(thePoint), [completionHandler](uint64_t result, WebKit::CallbackBase::Error error) {
-        void (^completionHandlerBlock)(NSUInteger) = (void (^)(NSUInteger))completionHandler.get();
-        if (error != WebKit::CallbackBase::Error::None) {
-            LOG(TextInput, &quot;    ...characterIndexForPoint failed.&quot;);
-            completionHandlerBlock(0);
-            return;
-        }
-        if (result == notFound)
-            result = NSNotFound;
-        LOG(TextInput, &quot;    -&gt; characterIndexForPoint returned %lu&quot;, result);
-        completionHandlerBlock(result);
-    });
-}
-
</del><span class="cx"> - (NSTextInputContext *)inputContext
</span><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;pluginComplexTextInputIdentifier()) {
-        ASSERT(!_data-&gt;_collectedKeypressCommands); // Should not get here from -_interpretKeyEvent:completionHandler:, we only use WKTextInputWindowController after giving the plug-in a chance to handle keydown natively.
-        return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
-    }
-
-    // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
-    if (!_data-&gt;_page-&gt;editorState().isContentEditable)
-        return nil;
-
-    return [super inputContext];
</del><ins>+    return _data-&gt;_impl-&gt;inputContext();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)unmarkText
-{
-    LOG(TextInput, &quot;unmarkText&quot;);
-
-    _data-&gt;_page-&gt;confirmCompositionAsync();
-}
-
-- (void)setMarkedText:(id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
-{
-    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
-    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
-
-    LOG(TextInput, &quot;setMarkedText:\&quot;%@\&quot; selectedRange:(%u, %u) replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, selectedRange.location, selectedRange.length, replacementRange.location, replacementRange.length);
-
-    Vector&lt;CompositionUnderline&gt; underlines;
-    NSString *text;
-
-    if (isAttributedString) {
-        // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
-        text = [string string];
-        extractUnderlines(string, underlines);
-    } else
-        text = string;
-
-    if (_data-&gt;_impl-&gt;inSecureInputState()) {
-        // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
-        // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
-        ASSERT(!_data-&gt;_page-&gt;editorState().hasComposition);
-        _data-&gt;_impl-&gt;notifyInputContextAboutDiscardedComposition();
-        // FIXME: We should store the command to handle it after DOM event processing, as it's regular keyboard input now, not a composition.
-        if ([text length] == 1 &amp;&amp; isASCII([text characterAtIndex:0]))
-            _data-&gt;_page-&gt;insertTextAsync(text, replacementRange);
-        else
-            NSBeep();
-        return;
-    }
-
-    _data-&gt;_page-&gt;setCompositionAsync(text, underlines, selectedRange, replacementRange);
-}
-
-// Synchronous NSTextInputClient is still implemented to catch spurious sync calls. Remove when that is no longer needed.
-
-- (NSRange)selectedRange NO_RETURN_DUE_TO_ASSERT
-{
-    ASSERT_NOT_REACHED();
-    return NSMakeRange(NSNotFound, 0);
-}
-
-- (BOOL)hasMarkedText NO_RETURN_DUE_TO_ASSERT
-{
-    ASSERT_NOT_REACHED();
-    return NO;
-}
-
-- (NSRange)markedRange NO_RETURN_DUE_TO_ASSERT
-{
-    ASSERT_NOT_REACHED();
-    return NSMakeRange(NSNotFound, 0);
-}
-
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange NO_RETURN_DUE_TO_ASSERT
-{
-    ASSERT_NOT_REACHED();
-    return nil;
-}
-
-- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint NO_RETURN_DUE_TO_ASSERT
-{
-    ASSERT_NOT_REACHED();
-    return 0;
-}
-
-- (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange NO_RETURN_DUE_TO_ASSERT
-{ 
-    ASSERT_NOT_REACHED();
-    return NSMakeRect(0, 0, 0, 0);
-}
-
</del><span class="cx"> - (BOOL)performKeyEquivalent:(NSEvent *)event
</span><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return NO;
-
-    // There's a chance that responding to this event will run a nested event loop, and
-    // fetching a new event might release the old one. Retaining and then autoreleasing
-    // the current event prevents that from causing a problem inside WebKit or AppKit code.
-    [[event retain] autorelease];
-
-    // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
-    // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
-    // Don't interpret this event again, avoiding re-entrancy and infinite loops.
-    if ([[event charactersIgnoringModifiers] isEqualToString:@&quot;\e&quot;] &amp;&amp; !([event modifierFlags] &amp; NSDeviceIndependentModifierFlagsMask))
-        return [super performKeyEquivalent:event];
-
-    if (_data-&gt;_keyDownEventBeingResent) {
-        // WebCore has already seen the event, no need for custom processing.
-        // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
-        // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
-        return [super performKeyEquivalent:event];
-    }
-
-    ASSERT(event == [NSApp currentEvent]);
-
-    _data-&gt;_impl-&gt;disableComplexTextInputIfNecessary();
-
-    // Pass key combos through WebCore if there is a key binding available for
-    // this event. This lets webpages have a crack at intercepting key-modified keypresses.
-    // FIXME: Why is the firstResponder check needed?
-    if (self == [[self window] firstResponder]) {
-        [self _interpretKeyEvent:event completionHandler:^(BOOL handledByInputMethod, const Vector&lt;KeypressCommand&gt;&amp; commands) {
-            _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
-        }];
-        return YES;
-    }
-    
-    return [super performKeyEquivalent:event];
</del><ins>+    return _data-&gt;_impl-&gt;performKeyEquivalent(event);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)keyUp:(NSEvent *)theEvent
</span><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
-
-    LOG(TextInput, &quot;keyUp:%p %@&quot;, theEvent, theEvent);
-
-    [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector&lt;KeypressCommand&gt;&amp; commands) {
-        ASSERT(!handledByInputMethod || commands.isEmpty());
-        _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
-    }];
</del><ins>+    _data-&gt;_impl-&gt;keyUp(theEvent);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)keyDown:(NSEvent *)theEvent
</span><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
-
-    LOG(TextInput, &quot;keyDown:%p %@%s&quot;, theEvent, theEvent, (theEvent == _data-&gt;_keyDownEventBeingResent) ? &quot; (re-sent)&quot; : &quot;&quot;);
-
-    if (_data-&gt;_impl-&gt;tryHandlePluginComplexTextInputKeyDown(theEvent)) {
-        LOG(TextInput, &quot;...handled by plug-in&quot;);
-        return;
-    }
-
-    // We could be receiving a key down from AppKit if we have re-sent an event
-    // that maps to an action that is currently unavailable (for example a copy when
-    // there is no range selection).
-    // If this is the case we should ignore the key down.
-    if (_data-&gt;_keyDownEventBeingResent == theEvent) {
-        [super keyDown:theEvent];
-        return;
-    }
-
-    [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector&lt;KeypressCommand&gt;&amp; commands) {
-        ASSERT(!handledByInputMethod || commands.isEmpty());
-        _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
-    }];
</del><ins>+    _data-&gt;_impl-&gt;keyDown(theEvent);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)flagsChanged:(NSEvent *)theEvent
</span><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
-
-    LOG(TextInput, &quot;flagsChanged:%p %@&quot;, theEvent, theEvent);
-
-    unsigned short keyCode = [theEvent keyCode];
-
-    // Don't make an event from the num lock and function keys
-    if (!keyCode || keyCode == 10 || keyCode == 63)
-        return;
-
-    [self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector&lt;KeypressCommand&gt;&amp; commands) {
-        _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
-    }];
</del><ins>+    _data-&gt;_impl-&gt;flagsChanged(theEvent);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#else // USE(ASYNC_NSTEXTINPUTCLIENT)
-
-- (BOOL)_interpretKeyEvent:(NSEvent *)event savingCommandsTo:(Vector&lt;WebCore::KeypressCommand&gt;&amp;)commands
</del><ins>+- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelectedRange replacementRange:(NSRange)replacementRange
</ins><span class="cx"> {
</span><del>-    ASSERT(!_data-&gt;_interpretKeyEventsParameters);
-    ASSERT(commands.isEmpty());
-
-    if ([event type] == NSFlagsChanged)
-        return NO;
-
-    WKViewInterpretKeyEventsParameters parameters;
-    parameters.eventInterpretationHadSideEffects = false;
-    parameters.executingSavedKeypressCommands = false;
-    // We assume that an input method has consumed the event, and only change this assumption if one of the NSTextInput methods is called.
-    // We assume the IM will *not* consume hotkey sequences.
-    parameters.consumedByIM = !([event modifierFlags] &amp; NSCommandKeyMask);
-    parameters.commands = &amp;commands;
-    _data-&gt;_interpretKeyEventsParameters = &amp;parameters;
-
-    LOG(TextInput, &quot;-&gt; interpretKeyEvents:%p %@&quot;, event, event);
-    [self interpretKeyEvents:[NSArray arrayWithObject:event]];
-
-    _data-&gt;_interpretKeyEventsParameters = nullptr;
-
-    // An input method may consume an event and not tell us (e.g. when displaying a candidate window),
-    // in which case we should not bubble the event up the DOM.
-    if (parameters.consumedByIM) {
-        ASSERT(commands.isEmpty());
-        LOG(TextInput, &quot;...event %p was consumed by an input method&quot;, event);
-        return YES;
-    }
-
-    LOG(TextInput, &quot;...interpretKeyEvents for event %p done, returns %d&quot;, event, parameters.eventInterpretationHadSideEffects);
-
-    // If we have already executed all or some of the commands, the event is &quot;handled&quot;. Note that there are additional checks on web process side.
-    return parameters.eventInterpretationHadSideEffects;
</del><ins>+    _data-&gt;_impl-&gt;setMarkedText(string, newSelectedRange, replacementRange);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)_executeSavedKeypressCommands
</del><ins>+- (void)unmarkText
</ins><span class="cx"> {
</span><del>-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-    if (!parameters || parameters-&gt;commands-&gt;isEmpty())
-        return;
-
-    // We could be called again if the execution of one command triggers a call to selectedRange.
-    // In this case, the state is up to date, and we don't need to execute any more saved commands to return a result.
-    if (parameters-&gt;executingSavedKeypressCommands)
-        return;
-
-    LOG(TextInput, &quot;Executing %u saved keypress commands...&quot;, parameters-&gt;commands-&gt;size());
-
-    parameters-&gt;executingSavedKeypressCommands = true;
-    parameters-&gt;eventInterpretationHadSideEffects |= _data-&gt;_page-&gt;executeKeypressCommands(*parameters-&gt;commands);
-    parameters-&gt;commands-&gt;clear();
-    parameters-&gt;executingSavedKeypressCommands = false;
-
-    LOG(TextInput, &quot;...done executing saved keypress commands.&quot;);
</del><ins>+    _data-&gt;_impl-&gt;unmarkText();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)doCommandBySelector:(SEL)selector
-{
-    LOG(TextInput, &quot;doCommandBySelector:\&quot;%s\&quot;&quot;, sel_getName(selector));
-
-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-    if (parameters)
-        parameters-&gt;consumedByIM = false;
-
-    // As in insertText:replacementRange:, we assume that the call comes from an input method if there is marked text.
-    bool isFromInputMethod = _data-&gt;_page-&gt;editorState().hasComposition;
-
-    if (parameters &amp;&amp; !isFromInputMethod) {
-        KeypressCommand command(NSStringFromSelector(selector));
-        parameters-&gt;commands-&gt;append(command);
-        LOG(TextInput, &quot;...stored&quot;);
-        _data-&gt;_page-&gt;registerKeypressCommandName(command.commandName);
-    } else {
-        // FIXME: Send the command to Editor synchronously and only send it along the
-        // responder chain if it's a selector that does not correspond to an editing command.
-        [super doCommandBySelector:selector];
-    }
-}
-
-- (void)insertText:(id)string
-{
-    // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
-    // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
-    // command ensures that a keypress event is dispatched as appropriate.
-    [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)];
-}
-
-- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
-{
-    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
-    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
-
-    if (replacementRange.location != NSNotFound)
-        LOG(TextInput, &quot;insertText:\&quot;%@\&quot; replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
-    else
-        LOG(TextInput, &quot;insertText:\&quot;%@\&quot;&quot;, isAttributedString ? [string string] : string);
-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-    if (parameters)
-        parameters-&gt;consumedByIM = false;
-
-    NSString *text;
-    bool isFromInputMethod = _data-&gt;_page-&gt;editorState().hasComposition;
-
-    Vector&lt;TextAlternativeWithRange&gt; dictationAlternatives;
-
-    if (isAttributedString) {
-#if USE(DICTATION_ALTERNATIVES)
-        collectDictationTextAlternatives(string, dictationAlternatives);
-#endif
-        // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
-        text = [string string];
-    } else
-        text = string;
-
-    // insertText can be called for several reasons:
-    // - If it's from normal key event processing (including key bindings), we may need to save the action to perform it later.
-    // - If it's from an input method, then we should insert the text now. We assume it's from the input method if we have marked text.
-    // FIXME: In theory, this could be wrong for some input methods, so we should try to find another way to determine if the call is from the input method.
-    // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
-    // then we also execute it immediately, as there will be no other chance.
-    if (parameters &amp;&amp; !isFromInputMethod) {
-        // FIXME: Handle replacementRange in this case, too. It's known to occur in practice when canceling Press and Hold (see &lt;rdar://11940670&gt;).
-        ASSERT(replacementRange.location == NSNotFound);
-        KeypressCommand command(&quot;insertText:&quot;, text);
-        parameters-&gt;commands-&gt;append(command);
-        _data-&gt;_page-&gt;registerKeypressCommandName(command.commandName);
-        return;
-    }
-
-    String eventText = text;
-    eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
-    bool eventHandled;
-    if (!dictationAlternatives.isEmpty())
-        eventHandled = _data-&gt;_page-&gt;insertDictatedText(eventText, replacementRange, dictationAlternatives);
-    else
-        eventHandled = _data-&gt;_page-&gt;insertText(eventText, replacementRange);
-
-    if (parameters)
-        parameters-&gt;eventInterpretationHadSideEffects |= eventHandled;
-}
-
-- (NSTextInputContext *)inputContext
-{
-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-
-    if (_data-&gt;_impl-&gt;pluginComplexTextInputIdentifier() &amp;&amp; !parameters)
-        return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
-
-    // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
-    if (!_data-&gt;_page-&gt;editorState().isContentEditable)
-        return nil;
-
-    return [super inputContext];
-}
-
</del><span class="cx"> - (NSRange)selectedRange
</span><span class="cx"> {
</span><del>-    [self _executeSavedKeypressCommands];
-
-    EditingRange selectedRange;
-    _data-&gt;_page-&gt;getSelectedRange(selectedRange);
-
-    NSRange result = selectedRange;
-    if (result.location == NSNotFound)
-        LOG(TextInput, &quot;selectedRange -&gt; (NSNotFound, %u)&quot;, result.length);
-    else
-        LOG(TextInput, &quot;selectedRange -&gt; (%u, %u)&quot;, result.location, result.length);
-
-    return result;
</del><ins>+    return _data-&gt;_impl-&gt;selectedRange();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)hasMarkedText
</span><span class="cx"> {
</span><del>-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-
-    BOOL result;
-    if (parameters) {
-        result = _data-&gt;_page-&gt;editorState().hasComposition;
-        if (result) {
-            // A saved command can confirm a composition, but it cannot start a new one.
-            [self _executeSavedKeypressCommands];
-            result = _data-&gt;_page-&gt;editorState().hasComposition;
-        }
-    } else {
-        EditingRange markedRange;
-        _data-&gt;_page-&gt;getMarkedRange(markedRange);
-        result = markedRange.location != notFound;
-    }
-
-    LOG(TextInput, &quot;hasMarkedText -&gt; %u&quot;, result);
-    return result;
</del><ins>+    return _data-&gt;_impl-&gt;hasMarkedText();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)unmarkText
-{
-    [self _executeSavedKeypressCommands];
-
-    LOG(TextInput, &quot;unmarkText&quot;);
-
-    // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-
-    if (parameters) {
-        parameters-&gt;eventInterpretationHadSideEffects = true;
-        parameters-&gt;consumedByIM = false;
-    }
-
-    _data-&gt;_page-&gt;confirmComposition();
-}
-
-- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelectedRange replacementRange:(NSRange)replacementRange
-{
-    [self _executeSavedKeypressCommands];
-
-    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
-    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
-
-    LOG(TextInput, &quot;setMarkedText:\&quot;%@\&quot; selectedRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, newSelectedRange.location, newSelectedRange.length);
-
-    // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
-    WKViewInterpretKeyEventsParameters* parameters = _data-&gt;_interpretKeyEventsParameters;
-
-    if (parameters) {
-        parameters-&gt;eventInterpretationHadSideEffects = true;
-        parameters-&gt;consumedByIM = false;
-    }
-    
-    Vector&lt;CompositionUnderline&gt; underlines;
-    NSString *text;
-
-    if (isAttributedString) {
-        // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
-        text = [string string];
-        extractUnderlines(string, underlines);
-    } else
-        text = string;
-
-    if (_data-&gt;_page-&gt;editorState().isInPasswordField) {
-        // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
-        // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
-        ASSERT(!_data-&gt;_page-&gt;editorState().hasComposition);
-        _data-&gt;_impl-&gt;notifyInputContextAboutDiscardedComposition();
-        if ([text length] == 1 &amp;&amp; [[text decomposedStringWithCanonicalMapping] characterAtIndex:0] &lt; 0x80) {
-            _data-&gt;_page-&gt;insertText(text, replacementRange);
-        } else
-            NSBeep();
-        return;
-    }
-
-    _data-&gt;_page-&gt;setComposition(text, underlines, newSelectedRange, replacementRange);
-}
-
</del><span class="cx"> - (NSRange)markedRange
</span><span class="cx"> {
</span><del>-    [self _executeSavedKeypressCommands];
-
-    EditingRange markedRange;
-    _data-&gt;_page-&gt;getMarkedRange(markedRange);
-
-    NSRange result = markedRange;
-    if (result.location == NSNotFound)
-        LOG(TextInput, &quot;markedRange -&gt; (NSNotFound, %u)&quot;, result.length);
-    else
-        LOG(TextInput, &quot;markedRange -&gt; (%u, %u)&quot;, result.location, result.length);
-
-    return result;
</del><ins>+    return _data-&gt;_impl-&gt;markedRange();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange
</span><span class="cx"> {
</span><del>-    [self _executeSavedKeypressCommands];
-
-    if (!_data-&gt;_page-&gt;editorState().isContentEditable) {
-        LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u) -&gt; nil&quot;, nsRange.location, nsRange.length);
-        return nil;
-    }
-
-    if (_data-&gt;_page-&gt;editorState().isInPasswordField)
-        return nil;
-
-    AttributedString result;
-    _data-&gt;_page-&gt;getAttributedSubstringFromRange(nsRange, result);
-
-    if (actualRange) {
-        *actualRange = nsRange;
-        actualRange-&gt;length = [result.string length];
-    }
-
-    LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u) -&gt; \&quot;%@\&quot;&quot;, nsRange.location, nsRange.length, [result.string string]);
-    return [[result.string retain] autorelease];
</del><ins>+    return _data-&gt;_impl-&gt;attributedSubstringForProposedRange(nsRange, actualRange);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
</span><span class="cx"> {
</span><del>-    [self _executeSavedKeypressCommands];
-
-    NSWindow *window = [self window];
-    
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
-    if (window)
-        thePoint = [window convertScreenToBase:thePoint];
-#pragma clang diagnostic pop
-    thePoint = [self convertPoint:thePoint fromView:nil];  // the point is relative to the main frame
-    
-    uint64_t result = _data-&gt;_page-&gt;characterIndexForPoint(IntPoint(thePoint));
-    if (result == notFound)
-        result = NSNotFound;
-    LOG(TextInput, &quot;characterIndexForPoint:(%f, %f) -&gt; %u&quot;, thePoint.x, thePoint.y, result);
-    return result;
</del><ins>+    return _data-&gt;_impl-&gt;characterIndexForPoint(thePoint);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
</span><del>-{ 
-    [self _executeSavedKeypressCommands];
</del><ins>+{
+    return _data-&gt;_impl-&gt;firstRectForCharacterRange(theRange, actualRange);
+}
</ins><span class="cx"> 
</span><del>-    // Just to match NSTextView's behavior. Regression tests cannot detect this;
-    // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
-    // (type something; try ranges (1, -1) and (2, -1).
-    if ((theRange.location + theRange.length &lt; theRange.location) &amp;&amp; (theRange.location + theRange.length != 0))
-        theRange.length = 0;
</del><ins>+#if USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx"> 
</span><del>-    if (theRange.location == NSNotFound) {
-        if (actualRange)
-            *actualRange = theRange;
-        LOG(TextInput, &quot;firstRectForCharacterRange:(NSNotFound, %u) -&gt; NSZeroRect&quot;, theRange.length);
-        return NSZeroRect;
-    }
-
-    NSRect resultRect = _data-&gt;_page-&gt;firstRectForCharacterRange(theRange);
-    resultRect = [self convertRect:resultRect toView:nil];
-    resultRect = [self.window convertRectToScreen:resultRect];
-
-    if (actualRange) {
-        // FIXME: Update actualRange to match the range of first rect.
-        *actualRange = theRange;
-    }
-
-    LOG(TextInput, &quot;firstRectForCharacterRange:(%u, %u) -&gt; (%f, %f, %f, %f)&quot;, theRange.location, theRange.length, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
-    return resultRect;
</del><ins>+- (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
+{
+    _data-&gt;_impl-&gt;selectedRangeWithCompletionHandler(completionHandlerPtr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (BOOL)performKeyEquivalent:(NSEvent *)event
</del><ins>+- (void)markedRangeWithCompletionHandler:(void(^)(NSRange markedRange))completionHandlerPtr
</ins><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return NO;
-
-    // There's a chance that responding to this event will run a nested event loop, and
-    // fetching a new event might release the old one. Retaining and then autoreleasing
-    // the current event prevents that from causing a problem inside WebKit or AppKit code.
-    [[event retain] autorelease];
-
-    // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
-    // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
-    // Don't interpret this event again, avoiding re-entrancy and infinite loops.
-    if ([[event charactersIgnoringModifiers] isEqualToString:@&quot;\e&quot;] &amp;&amp; !([event modifierFlags] &amp; NSDeviceIndependentModifierFlagsMask))
-        return [super performKeyEquivalent:event];
-
-    if (_data-&gt;_keyDownEventBeingResent) {
-        // WebCore has already seen the event, no need for custom processing.
-        // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
-        // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
-        return [super performKeyEquivalent:event];
-    }
-
-    ASSERT(event == [NSApp currentEvent]);
-
-    _data-&gt;_impl-&gt;disableComplexTextInputIfNecessary();
-
-    // Pass key combos through WebCore if there is a key binding available for
-    // this event. This lets webpages have a crack at intercepting key-modified keypresses.
-    // FIXME: Why is the firstResponder check needed?
-    if (self == [[self window] firstResponder]) {
-        Vector&lt;KeypressCommand&gt; commands;
-        BOOL handledByInputMethod = [self _interpretKeyEvent:event savingCommandsTo:commands];
-        _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
-        return YES;
-    }
-    
-    return [super performKeyEquivalent:event];
</del><ins>+    _data-&gt;_impl-&gt;markedRangeWithCompletionHandler(completionHandlerPtr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)keyUp:(NSEvent *)theEvent
</del><ins>+- (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandlerPtr
</ins><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
-
-    LOG(TextInput, &quot;keyUp:%p %@&quot;, theEvent, theEvent);
-    // We don't interpret the keyUp event, as this breaks key bindings (see &lt;https://bugs.webkit.org/show_bug.cgi?id=130100&gt;).
-    _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, false, Vector&lt;KeypressCommand&gt;()));
</del><ins>+    _data-&gt;_impl-&gt;hasMarkedTextWithCompletionHandler(completionHandlerPtr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)keyDown:(NSEvent *)theEvent
</del><ins>+- (void)attributedSubstringForProposedRange:(NSRange)nsRange completionHandler:(void(^)(NSAttributedString *attrString, NSRange actualRange))completionHandlerPtr
</ins><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
-
-    LOG(TextInput, &quot;keyDown:%p %@%s&quot;, theEvent, theEvent, (theEvent == _data-&gt;_keyDownEventBeingResent) ? &quot; (re-sent)&quot; : &quot;&quot;);
-
-    // There's a chance that responding to this event will run a nested event loop, and
-    // fetching a new event might release the old one. Retaining and then autoreleasing
-    // the current event prevents that from causing a problem inside WebKit or AppKit code.
-    [[theEvent retain] autorelease];
-
-    if (_data-&gt;_impl-&gt;tryHandlePluginComplexTextInputKeyDown(theEvent)) {
-        LOG(TextInput, &quot;...handled by plug-in&quot;);
-        return;
-    }
-
-    // We could be receiving a key down from AppKit if we have re-sent an event
-    // that maps to an action that is currently unavailable (for example a copy when
-    // there is no range selection).
-    // If this is the case we should ignore the key down.
-    if (_data-&gt;_keyDownEventBeingResent == theEvent) {
-        [super keyDown:theEvent];
-        return;
-    }
-
-    Vector&lt;KeypressCommand&gt; commands;
-    BOOL handledByInputMethod = [self _interpretKeyEvent:theEvent savingCommandsTo:commands];
-    if (!commands.isEmpty()) {
-        // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
-        // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
-        // should be handled like normal text input after DOM event dispatch.
-        handledByInputMethod = NO;
-    }
-
-    _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, handledByInputMethod, commands));
</del><ins>+    _data-&gt;_impl-&gt;attributedSubstringForProposedRange(nsRange, completionHandlerPtr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)flagsChanged:(NSEvent *)theEvent
</del><ins>+- (void)firstRectForCharacterRange:(NSRange)theRange completionHandler:(void(^)(NSRect firstRect, NSRange actualRange))completionHandlerPtr
</ins><span class="cx"> {
</span><del>-    if (_data-&gt;_impl-&gt;ignoresNonWheelEvents())
-        return;
</del><ins>+    _data-&gt;_impl-&gt;firstRectForCharacterRange(theRange, completionHandlerPtr);
+}
</ins><span class="cx"> 
</span><del>-    LOG(TextInput, &quot;flagsChanged:%p %@&quot;, theEvent, theEvent);
-
-    // There's a chance that responding to this event will run a nested event loop, and
-    // fetching a new event might release the old one. Retaining and then autoreleasing
-    // the current event prevents that from causing a problem inside WebKit or AppKit code.
-    [[theEvent retain] autorelease];
-
-    unsigned short keyCode = [theEvent keyCode];
-
-    // Don't make an event from the num lock and function keys
-    if (!keyCode || keyCode == 10 || keyCode == 63)
-        return;
-
-    _data-&gt;_page-&gt;handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, false, Vector&lt;KeypressCommand&gt;()));
</del><ins>+- (void)characterIndexForPoint:(NSPoint)thePoint completionHandler:(void(^)(NSUInteger))completionHandlerPtr
+{
+    _data-&gt;_impl-&gt;characterIndexForPoint(thePoint, completionHandlerPtr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #endif // USE(ASYNC_NSTEXTINPUTCLIENT)
</span><span class="lines">@@ -1731,6 +888,16 @@
</span><span class="cx">     [super doCommandBySelector:selector];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (BOOL)_superPerformKeyEquivalent:(NSEvent *)event
+{
+    return [super performKeyEquivalent:event];
+}
+
+- (void)_superKeyDown:(NSEvent *)event
+{
+    [super keyDown:event];
+}
+
</ins><span class="cx"> - (NSArray *)validAttributesForMarkedText
</span><span class="cx"> {
</span><span class="cx">     static NSArray *validAttributes;
</span><span class="lines">@@ -1892,30 +1059,6 @@
</span><span class="cx">     _data-&gt;_impl-&gt;quickLookWithEvent(event);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)_doneWithKeyEvent:(NSEvent *)event eventWasHandled:(BOOL)eventWasHandled
-{
-    if ([event type] != NSKeyDown)
-        return;
-
-    if (_data-&gt;_impl-&gt;tryPostProcessPluginComplexTextInputKeyDown(event))
-        return;
-    
-    if (eventWasHandled) {
-        [NSCursor setHiddenUntilMouseMoves:YES];
-        return;
-    }
-
-    // resending the event may destroy this WKView
-    RetainPtr&lt;WKView&gt; protector(self);
-
-    ASSERT(!_data-&gt;_keyDownEventBeingResent);
-    _data-&gt;_keyDownEventBeingResent = event;
-    [NSApp _setCurrentEvent:event];
-    [NSApp sendEvent:event];
-
-    _data-&gt;_keyDownEventBeingResent = nullptr;
-}
-
</del><span class="cx"> - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
</span><span class="cx"> {
</span><span class="cx">     return _data-&gt;_impl-&gt;addTrackingRect(NSRectToCGRect(rect), owner, data, assumeInside);
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPImacWKViewInternalh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -50,7 +50,6 @@
</span><span class="cx"> @property (nonatomic, setter=_setThumbnailView:) _WKThumbnailView *_thumbnailView;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-- (void)_doneWithKeyEvent:(NSEvent *)event eventWasHandled:(BOOL)eventWasHandled;
</del><span class="cx"> - (void)_addFontPanelObserver;
</span><span class="cx"> 
</span><span class="cx"> @end
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebViewImplh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.h        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -59,6 +59,8 @@
</span><span class="cx"> - (void)_superSmartMagnifyWithEvent:(NSEvent *)event;
</span><span class="cx"> - (id)_superAccessibilityAttributeValue:(NSString *)attribute;
</span><span class="cx"> - (void)_superDoCommandBySelector:(SEL)selector;
</span><ins>+- (BOOL)_superPerformKeyEquivalent:(NSEvent *)event;
+- (void)_superKeyDown:(NSEvent *)event;
</ins><span class="cx"> 
</span><span class="cx"> // This is a hack; these things live can live on a category (e.g. WKView (Private)) but WKView itself conforms to this protocol.
</span><span class="cx"> // They're not actually optional.
</span><span class="lines">@@ -74,6 +76,10 @@
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><ins>+namespace WebCore {
+struct KeyPressCommand;
+}
+
</ins><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> class DrawingAreaProxy;
</span><span class="lines">@@ -86,6 +92,15 @@
</span><span class="cx"> typedef Vector&lt;RetainPtr&lt;ValidationItem&gt;&gt; ValidationVector;
</span><span class="cx"> typedef HashMap&lt;String, ValidationVector&gt; ValidationMap;
</span><span class="cx"> 
</span><ins>+#if !USE(ASYNC_NSTEXTINPUTCLIENT)
+struct WKViewInterpretKeyEventsParameters {
+    bool eventInterpretationHadSideEffects;
+    bool consumedByIM;
+    bool executingSavedKeypressCommands;
+    Vector&lt;WebCore::KeypressCommand&gt;* commands;
+};
+#endif
+
</ins><span class="cx"> class WebViewImpl {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(WebViewImpl);
</span><span class="lines">@@ -392,6 +407,33 @@
</span><span class="cx">     void setTotalHeightOfBanners(CGFloat totalHeightOfBanners) { m_totalHeightOfBanners = totalHeightOfBanners; }
</span><span class="cx">     CGFloat totalHeightOfBanners() const { return m_totalHeightOfBanners; }
</span><span class="cx"> 
</span><ins>+    void doneWithKeyEvent(NSEvent *, bool eventWasHandled);
+    void doCommandBySelector(SEL);
+    void insertText(id string);
+    void insertText(id string, NSRange replacementRange);
+    NSTextInputContext *inputContext();
+    void unmarkText();
+    void setMarkedText(id string, NSRange selectedRange, NSRange replacementRange);
+    NSRange selectedRange();
+    bool hasMarkedText();
+    NSRange markedRange();
+    NSAttributedString *attributedSubstringForProposedRange(NSRange, NSRangePointer actualRange);
+    NSUInteger characterIndexForPoint(NSPoint);
+    NSRect firstRectForCharacterRange(NSRange, NSRangePointer actualRange);
+    bool performKeyEquivalent(NSEvent *);
+    void keyUp(NSEvent *);
+    void keyDown(NSEvent *);
+    void flagsChanged(NSEvent *);
+
+#if USE(ASYNC_NSTEXTINPUTCLIENT)
+    void selectedRangeWithCompletionHandler(void(^)(NSRange));
+    void hasMarkedTextWithCompletionHandler(void(^)(BOOL hasMarkedText));
+    void markedRangeWithCompletionHandler(void(^)(NSRange));
+    void attributedSubstringForProposedRange(NSRange, void(^)(NSAttributedString *attrString, NSRange actualRange));
+    void firstRectForCharacterRange(NSRange, void(^)(NSRect firstRect, NSRange actualRange));
+    void characterIndexForPoint(NSPoint, void(^)(NSUInteger));
+#endif // USE(ASYNC_NSTEXTINPUTCLIENT)
+
</ins><span class="cx"> private:
</span><span class="cx">     WeakPtr&lt;WebViewImpl&gt; createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
</span><span class="cx"> 
</span><span class="lines">@@ -411,6 +453,14 @@
</span><span class="cx"> 
</span><span class="cx">     void setUserInterfaceItemState(NSString *commandName, bool enabled, int state);
</span><span class="cx"> 
</span><ins>+#if USE(ASYNC_NSTEXTINPUTCLIENT)
+    void collectKeyboardLayoutCommandsForEvent(NSEvent *, Vector&lt;WebCore::KeypressCommand&gt;&amp;);
+    void interpretKeyEvent(NSEvent *, void(^completionHandler)(BOOL handled, const Vector&lt;WebCore::KeypressCommand&gt;&amp;));
+#else
+    void executeSavedKeypressCommands();
+    bool interpretKeyEvent(NSEvent *, Vector&lt;WebCore::KeypressCommand&gt;&amp;);
+#endif
+
</ins><span class="cx">     NSView &lt;WebViewImplDelegate&gt; *m_view;
</span><span class="cx">     WebPageProxy&amp; m_page;
</span><span class="cx">     PageClient&amp; m_pageClient;
</span><span class="lines">@@ -516,6 +566,16 @@
</span><span class="cx">     CGFloat m_totalHeightOfBanners { 0 };
</span><span class="cx"> 
</span><span class="cx">     RetainPtr&lt;NSView&gt; m_inspectorAttachmentView;
</span><ins>+
+    // We keep here the event when resending it to
+    // the application to distinguish the case of a new event from one
+    // that has been already sent to WebCore.
+    RetainPtr&lt;NSEvent&gt; m_keyDownEventBeingResent;
+#if USE(ASYNC_NSTEXTINPUTCLIENT)
+    Vector&lt;WebCore::KeypressCommand&gt;* m_collectedKeypressCommands;
+#else
+    WKViewInterpretKeyEventsParameters* m_interpretKeyEventsParameters;
+#endif
</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 (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebViewImpl.mm        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -74,6 +74,8 @@
</span><span class="cx"> #import &lt;WebCore/NSWindowSPI.h&gt;
</span><span class="cx"> #import &lt;WebCore/PlatformEventFactoryMac.h&gt;
</span><span class="cx"> #import &lt;WebCore/SoftLinking.h&gt;
</span><ins>+#import &lt;WebCore/TextAlternativeWithRange.h&gt;
+#import &lt;WebCore/TextUndoInsertionMarkupMac.h&gt;
</ins><span class="cx"> #import &lt;WebCore/ViewState.h&gt;
</span><span class="cx"> #import &lt;WebCore/WebActionDisablingCALayerDelegate.h&gt;
</span><span class="cx"> #import &lt;WebCore/WebCoreCALayerExtras.h&gt;
</span><span class="lines">@@ -85,6 +87,15 @@
</span><span class="cx"> 
</span><span class="cx"> SOFT_LINK_CONSTANT_MAY_FAIL(Lookup, LUNotificationPopoverWillClose, NSString *)
</span><span class="cx"> 
</span><ins>+// FIXME: Move to an SPI header.
+#if USE(ASYNC_NSTEXTINPUTCLIENT)
+@interface NSTextInputContext (WKNSTextInputContextDetails)
+- (void)handleEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
+- (void)handleEventByInputMethod:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
+- (BOOL)handleEventByKeyboardLayout:(NSEvent *)event;
+@end
+#endif
+
</ins><span class="cx"> @interface WKWindowVisibilityObserver : NSObject {
</span><span class="cx">     NSView *_view;
</span><span class="cx">     WebKit::WebViewImpl *_impl;
</span><span class="lines">@@ -532,7 +543,7 @@
</span><span class="cx">         NSEvent *keyboardEvent = nil;
</span><span class="cx">         if ([event type] == NSKeyDown || [event type] == NSKeyUp)
</span><span class="cx">             keyboardEvent = event;
</span><del>-        m_page.setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, Vector&lt;WebCore::KeypressCommand&gt;()), [](WebKit::CallbackBase::Error) { });
</del><ins>+        m_page.setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, { }), [](WebKit::CallbackBase::Error) { });
</ins><span class="cx">     }
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="lines">@@ -3068,6 +3079,966 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebViewImpl::doneWithKeyEvent(NSEvent *event, bool eventWasHandled)
+{
+    if ([event type] != NSKeyDown)
+        return;
+
+    if (tryPostProcessPluginComplexTextInputKeyDown(event))
+        return;
+
+    if (eventWasHandled) {
+        [NSCursor setHiddenUntilMouseMoves:YES];
+        return;
+    }
+
+    // resending the event may destroy this WKView
+    RetainPtr&lt;NSView&gt; protector(m_view);
+
+    ASSERT(!m_keyDownEventBeingResent);
+    m_keyDownEventBeingResent = event;
+    [NSApp _setCurrentEvent:event];
+    [NSApp sendEvent:event];
+    
+    m_keyDownEventBeingResent = nullptr;
+}
+
+static Vector&lt;WebCore::CompositionUnderline&gt; extractUnderlines(NSAttributedString *string)
+{
+    Vector&lt;WebCore::CompositionUnderline&gt; result;
+    int length = string.string.length;
+
+    for (int i = 0; i &lt; length;) {
+        NSRange range;
+        NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&amp;range inRange:NSMakeRange(i, length - i)];
+
+        if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
+            WebCore::Color color = WebCore::Color::black;
+            if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
+                color = WebCore::colorFromNSColor(colorAttr);
+            result.append(WebCore::CompositionUnderline(range.location, NSMaxRange(range), color, style.intValue &gt; 1));
+        }
+        
+        i = range.location + range.length;
+    }
+
+    return result;
+}
+
+static bool eventKeyCodeIsZeroOrNumLockOrFn(NSEvent *event)
+{
+    unsigned short keyCode = [event keyCode];
+    return !keyCode || keyCode == 10 || keyCode == 63;
+}
+
+#if USE(ASYNC_NSTEXTINPUTCLIENT)
+
+Vector&lt;WebCore::KeypressCommand&gt; WebViewImpl::collectKeyboardLayoutCommandsForEvent(NSEvent *event)
+{
+    Vector&lt;WebCore::KeypressCommand&gt;&amp; commands;
+
+    if ([event type] != NSKeyDown)
+        return;
+
+    ASSERT(!m_collectedKeypressCommands);
+    m_collectedKeypressCommands = &amp;commands;
+
+    if (NSTextInputContext *context = inputContext())
+        [context handleEventByKeyboardLayout:event];
+    else
+        [m_view interpretKeyEvents:[NSArray arrayWithObject:event]];
+
+    m_collectedKeypressCommands = nullptr;
+
+    return commands;
+}
+
+void WebViewImpl::interpretKeyEvent(NSEvent *event, void(^completionHandler)(BOOL handled, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands))
+{
+    // For regular Web content, input methods run before passing a keydown to DOM, but plug-ins get an opportunity to handle the event first.
+    // There is no need to collect commands, as the plug-in cannot execute them.
+    if (pluginComplexTextInputIdentifier()) {
+        completionHandler(NO, { });
+        return;
+    }
+
+    if (!inputContext()) {
+        auto commands = collectKeyboardLayoutCommandsForEvent(event);
+        completionHandler(NO, commands);
+        return;
+    }
+
+    LOG(TextInput, &quot;-&gt; handleEventByInputMethod:%p %@&quot;, event, event);
+    [inputContext() handleEventByInputMethod:event completionHandler:^(BOOL handled) {
+        
+        LOG(TextInput, &quot;... handleEventByInputMethod%s handled&quot;, handled ? &quot;&quot; : &quot; not&quot;);
+        if (handled) {
+            completionHandler(YES, { });
+            return;
+        }
+
+        auto commands = collectKeyboardLayoutCommandsForEvent(event);
+        completionHandler(NO, commands);
+    }];
+}
+
+void WebViewImpl::doCommandBySelector(SEL selector)
+{
+    LOG(TextInput, &quot;doCommandBySelector:\&quot;%s\&quot;&quot;, sel_getName(selector));
+
+    if (auto* keypressCommands = m_collectedKeypressCommands) {
+        WebCore::KeypressCommand command(NSStringFromSelector(selector));
+        keypressCommands-&gt;append(command);
+        LOG(TextInput, &quot;...stored&quot;);
+        m_page.registerKeypressCommandName(command.commandName);
+    } else {
+        // FIXME: Send the command to Editor synchronously and only send it along the
+        // responder chain if it's a selector that does not correspond to an editing command.
+        [m_view _superDoCommandBySelector:selector];
+    }
+}
+
+void WebViewImpl::insertText(id string)
+{
+    // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
+    // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
+    // command ensures that a keypress event is dispatched as appropriate.
+    insertText(string, NSMakeRange(NSNotFound, 0));
+}
+
+void WebViewImpl::insertText(id string, NSRange replacementRange)
+{
+    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
+    if (replacementRange.location != NSNotFound)
+        LOG(TextInput, &quot;insertText:\&quot;%@\&quot; replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
+    else
+        LOG(TextInput, &quot;insertText:\&quot;%@\&quot;&quot;, isAttributedString ? [string string] : string);
+
+    NSString *text;
+    Vector&lt;WebCore::TextAlternativeWithRange&gt; dictationAlternatives;
+
+    bool registerUndoGroup = false;
+    if (isAttributedString) {
+#if USE(DICTATION_ALTERNATIVES)
+        WebCore::collectDictationTextAlternatives(string, dictationAlternatives);
+#endif
+#if USE(INSERTION_UNDO_GROUPING)
+        registerUndoGroup = WebCore::shouldRegisterInsertionUndoGroup(string);
+#endif
+        // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
+        text = [string string];
+    } else
+        text = string;
+
+    // insertText can be called for several reasons:
+    // - If it's from normal key event processing (including key bindings), we save the action to perform it later.
+    // - If it's from an input method, then we should insert the text now.
+    // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
+    // then we also execute it immediately, as there will be no other chance.
+    Vector&lt;WebCore::KeypressCommand&gt;* keypressCommands = m_collectedKeypressCommands;
+    if (keypressCommands) {
+        ASSERT(replacementRange.location == NSNotFound);
+        WebCore::KeypressCommand command(&quot;insertText:&quot;, text);
+        keypressCommands-&gt;append(command);
+        LOG(TextInput, &quot;...stored&quot;);
+        m_page.registerKeypressCommandName(command.commandName);
+        return;
+    }
+
+    String eventText = text;
+    eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
+    if (!dictationAlternatives.isEmpty())
+        m_page.insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
+    else
+        m_page.insertTextAsync(eventText, replacementRange, registerUndoGroup);
+}
+
+void WebViewImpl::selectedRangeWithCompletionHandler(void(^completionHandlerPtr)(NSRange selectedRange))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;selectedRange&quot;);
+    m_page.getSelectedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
+        void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...selectedRange failed.&quot;);
+            completionHandlerBlock(NSMakeRange(NSNotFound, 0));
+            return;
+        }
+        NSRange result = editingRangeResult;
+        if (result.location == NSNotFound)
+            LOG(TextInput, &quot;    -&gt; selectedRange returned (NSNotFound, %llu)&quot;, result.length);
+        else
+            LOG(TextInput, &quot;    -&gt; selectedRange returned (%llu, %llu)&quot;, result.location, result.length);
+        completionHandlerBlock(result);
+    });
+}
+
+void WebViewImpl::markedRangeWithCompletionHandler(void(^completionHandlerPtr)(NSRange markedRange))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;markedRange&quot;);
+    m_page.getMarkedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
+        void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...markedRange failed.&quot;);
+            completionHandlerBlock(NSMakeRange(NSNotFound, 0));
+            return;
+        }
+        NSRange result = editingRangeResult;
+        if (result.location == NSNotFound)
+            LOG(TextInput, &quot;    -&gt; markedRange returned (NSNotFound, %llu)&quot;, result.length);
+        else
+            LOG(TextInput, &quot;    -&gt; markedRange returned (%llu, %llu)&quot;, result.location, result.length);
+        completionHandlerBlock(result);
+    });
+}
+
+void WebViewImpl::hasMarkedTextWithCompletionHandler(void(^completionHandlerPtr)(BOOL hasMarkedText))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;hasMarkedText&quot;);
+    m_page.getMarkedRangeAsync([completionHandler](const EditingRange&amp; editingRangeResult, WebKit::CallbackBase::Error error) {
+        void (^completionHandlerBlock)(BOOL) = (void (^)(BOOL))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...hasMarkedText failed.&quot;);
+            completionHandlerBlock(NO);
+            return;
+        }
+        BOOL hasMarkedText = editingRangeResult.location != notFound;
+        LOG(TextInput, &quot;    -&gt; hasMarkedText returned %u&quot;, hasMarkedText);
+        completionHandlerBlock(hasMarkedText);
+    });
+}
+
+void WebViewImpl::attributedSubstringForProposedRange(NSRange proposedRange, void(^completionHandlerPtr)(NSAttributedString *attrString, NSRange actualRange))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u)&quot;, proposedRange.location, proposedRange.length);
+    m_page.attributedSubstringForCharacterRangeAsync(proposedRange, [completionHandler](const AttributedString&amp; string, const EditingRange&amp; actualRange, WebKit::CallbackBase::Error error) {
+        void (^completionHandlerBlock)(NSAttributedString *, NSRange) = (void (^)(NSAttributedString *, NSRange))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...attributedSubstringFromRange failed.&quot;);
+            completionHandlerBlock(0, NSMakeRange(NSNotFound, 0));
+            return;
+        }
+        LOG(TextInput, &quot;    -&gt; attributedSubstringFromRange returned %@&quot;, [string.string.get() string]);
+        completionHandlerBlock([[string.string.get() retain] autorelease], actualRange);
+    });
+}
+
+void WebViewImpl::firstRectForCharacterRange(NSRange range, void(^completionHandlerPtr)(NSRect firstRect, NSRange actualRange))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;firstRectForCharacterRange:(%u, %u)&quot;, range.location, range.length);
+
+    // Just to match NSTextView's behavior. Regression tests cannot detect this;
+    // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
+    // (type something; try ranges (1, -1) and (2, -1).
+    if ((range.location + range.length &lt; range.location) &amp;&amp; (range.location + range.length != 0))
+        range.length = 0;
+
+    if (range.location == NSNotFound) {
+        LOG(TextInput, &quot;    -&gt; NSZeroRect&quot;);
+        completionHandlerPtr(NSZeroRect, range);
+        return;
+    }
+
+    auto weakThis = createWeakPtr();
+    m_page.firstRectForCharacterRangeAsync(range, [weakThis, completionHandler](const WebCore::IntRect&amp; rect, const EditingRange&amp; actualRange, WebKit::CallbackBase::Error error) {
+        if (!weakThis)
+            return;
+
+        void (^completionHandlerBlock)(NSRect, NSRange) = (void (^)(NSRect, NSRange))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...firstRectForCharacterRange failed.&quot;);
+            completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
+            return;
+        }
+
+        NSRect resultRect = [weakThis-&gt;m_view convertRect:rect toView:nil];
+        resultRect = [weakThis-&gt;m_view.window convertRectToScreen:resultRect];
+
+        LOG(TextInput, &quot;    -&gt; firstRectForCharacterRange returned (%f, %f, %f, %f)&quot;, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
+        completionHandlerBlock(resultRect, actualRange);
+    });
+}
+
+void WebViewImpl::characterIndexForPoint(NSPoint point, void(^completionHandlerPtr)(NSUInteger))
+{
+    auto completionHandler = adoptNS([completionHandlerPtr copy]);
+
+    LOG(TextInput, &quot;characterIndexForPoint:(%f, %f)&quot;, point.x, point.y);
+
+    NSWindow *window = m_view.window;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
+    if (window)
+        point = [window convertScreenToBase:point];
+#pragma clang diagnostic pop
+    point = [m_view convertPoint:point fromView:nil];  // the point is relative to the main frame
+
+    m_page.characterIndexForPointAsync(WebCore::IntPoint(point), [completionHandler](uint64_t result, WebKit::CallbackBase::Error error) {
+        void (^completionHandlerBlock)(NSUInteger) = (void (^)(NSUInteger))completionHandler.get();
+        if (error != WebKit::CallbackBase::Error::None) {
+            LOG(TextInput, &quot;    ...characterIndexForPoint failed.&quot;);
+            completionHandlerBlock(0);
+            return;
+        }
+        if (result == notFound)
+            result = NSNotFound;
+        LOG(TextInput, &quot;    -&gt; characterIndexForPoint returned %lu&quot;, result);
+        completionHandlerBlock(result);
+    });
+}
+
+NSTextInputContext *WebViewImpl::inputContext()
+{
+    if (pluginComplexTextInputIdentifier()) {
+        ASSERT(!m_collectedKeypressCommands); // Should not get here from -_interpretKeyEvent:completionHandler:, we only use WKTextInputWindowController after giving the plug-in a chance to handle keydown natively.
+        return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
+    }
+
+    // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
+    if (!m_page.editorState().isContentEditable)
+        return nil;
+
+    return [m_view _superInputContext];
+}
+
+void WebViewImpl::unmarkText()
+{
+    LOG(TextInput, &quot;unmarkText&quot;);
+
+    m_page.confirmCompositionAsync();
+}
+
+void WebViewImpl::setMarkedText(id string, NSRange selectedRange, NSRange replacementRange)
+{
+    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
+    LOG(TextInput, &quot;setMarkedText:\&quot;%@\&quot; selectedRange:(%u, %u) replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, selectedRange.location, selectedRange.length, replacementRange.location, replacementRange.length);
+
+    Vector&lt;WebCore::CompositionUnderline&gt; underlines;
+    NSString *text;
+
+    if (isAttributedString) {
+        // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
+        text = [string string];
+        underlines = extractUnderlines(string);
+    } else
+        text = string;
+
+    if (inSecureInputState()) {
+        // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
+        // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
+        ASSERT(!m_page.editorState().hasComposition);
+        notifyInputContextAboutDiscardedComposition();
+        // FIXME: We should store the command to handle it after DOM event processing, as it's regular keyboard input now, not a composition.
+        if ([text length] == 1 &amp;&amp; isASCII([text characterAtIndex:0]))
+            m_page.insertTextAsync(text, replacementRange);
+        else
+            NSBeep();
+        return;
+    }
+
+    m_page.setCompositionAsync(text, underlines, selectedRange, replacementRange);
+}
+
+// Synchronous NSTextInputClient is still implemented to catch spurious sync calls. Remove when that is no longer needed.
+
+NSRange WebViewImpl::selectedRange()
+{
+    ASSERT_NOT_REACHED();
+    return NSMakeRange(NSNotFound, 0);
+}
+
+bool WebViewImpl::hasMarkedText()
+{
+    ASSERT_NOT_REACHED();
+    return NO;
+}
+
+NSRange WebViewImpl::markedRange()
+{
+    ASSERT_NOT_REACHED();
+    return NSMakeRange(NSNotFound, 0);
+}
+
+NSAttributedString *WebViewImpl::attributedSubstringForProposedRange(NSRange nsRange, NSRangePointer actualRange)
+{
+    ASSERT_NOT_REACHED();
+    return nil;
+}
+
+NSUInteger WebViewImpl::characterIndexForPoint(NSPoint point)
+{
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+NSRect WebViewImpl::firstRectForCharacterRange(NSRange range, NSRangePointer actualRange)
+{
+    ASSERT_NOT_REACHED();
+    return NSZeroRect;
+}
+
+bool WebViewImpl::performKeyEquivalent(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return NO;
+
+    // There's a chance that responding to this event will run a nested event loop, and
+    // fetching a new event might release the old one. Retaining and then autoreleasing
+    // the current event prevents that from causing a problem inside WebKit or AppKit code.
+    [[event retain] autorelease];
+
+    // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
+    // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
+    // Don't interpret this event again, avoiding re-entrancy and infinite loops.
+    if ([[event charactersIgnoringModifiers] isEqualToString:@&quot;\e&quot;] &amp;&amp; !([event modifierFlags] &amp; NSDeviceIndependentModifierFlagsMask))
+        return [m_view _superPerformKeyEquivalent:event];
+
+    if (m_keyDownEventBeingResent) {
+        // WebCore has already seen the event, no need for custom processing.
+        // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
+        // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
+        return [m_view _superPerformKeyEquivalent:event];
+    }
+
+    ASSERT(event == [NSApp currentEvent]);
+
+    disableComplexTextInputIfNecessary();
+
+    // Pass key combos through WebCore if there is a key binding available for
+    // this event. This lets webpages have a crack at intercepting key-modified keypresses.
+    // FIXME: Why is the firstResponder check needed?
+    if (m_view == m_view.window.firstResponder) {
+        interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
+            m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+        });
+        return YES;
+    }
+    
+    return [m_view _superPerformKeyEquivalent:event];
+}
+
+void WebViewImpl::keyUp(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;keyUp:%p %@&quot;, event, event);
+
+    interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
+        ASSERT(!handledByInputMethod || commands.isEmpty());
+        m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+    });
+}
+
+void WebViewImpl::keyDown(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;keyDown:%p %@%s&quot;, event, event, (event == m_keyDownEventBeingResent) ? &quot; (re-sent)&quot; : &quot;&quot;);
+
+    if (tryHandlePluginComplexTextInputKeyDown(event)) {
+        LOG(TextInput, &quot;...handled by plug-in&quot;);
+        return;
+    }
+
+    // We could be receiving a key down from AppKit if we have re-sent an event
+    // that maps to an action that is currently unavailable (for example a copy when
+    // there is no range selection).
+    // If this is the case we should ignore the key down.
+    if (m_keyDownEventBeingResent == event) {
+        [m_view _superKeyDown:event];
+        return;
+    }
+
+    interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
+        ASSERT(!handledByInputMethod || commands.isEmpty());
+        m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+    });
+}
+
+void WebViewImpl::flagsChanged(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;flagsChanged:%p %@&quot;, event, event);
+
+    // Don't make an event from the num lock and function keys
+    if (eventKeyCodeIsZeroOrNumLockOrFn(event))
+        return;
+
+    interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector&lt;WebCore::KeypressCommand&gt;&amp; commands) {
+        m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+    });
+}
+
+#else // USE(ASYNC_NSTEXTINPUTCLIENT)
+
+bool WebViewImpl::interpretKeyEvent(NSEvent *event, Vector&lt;WebCore::KeypressCommand&gt;&amp; commands)
+{
+    ASSERT(!m_interpretKeyEventsParameters);
+    ASSERT(commands.isEmpty());
+
+    if ([event type] == NSFlagsChanged)
+        return NO;
+
+    WKViewInterpretKeyEventsParameters parameters;
+    parameters.eventInterpretationHadSideEffects = false;
+    parameters.executingSavedKeypressCommands = false;
+    // We assume that an input method has consumed the event, and only change this assumption if one of the NSTextInput methods is called.
+    // We assume the IM will *not* consume hotkey sequences.
+    parameters.consumedByIM = !([event modifierFlags] &amp; NSCommandKeyMask);
+    parameters.commands = &amp;commands;
+    m_interpretKeyEventsParameters = &amp;parameters;
+
+    LOG(TextInput, &quot;-&gt; interpretKeyEvents:%p %@&quot;, event, event);
+    [m_view interpretKeyEvents:[NSArray arrayWithObject:event]];
+
+    m_interpretKeyEventsParameters = nullptr;
+
+    // An input method may consume an event and not tell us (e.g. when displaying a candidate window),
+    // in which case we should not bubble the event up the DOM.
+    if (parameters.consumedByIM) {
+        ASSERT(commands.isEmpty());
+        LOG(TextInput, &quot;...event %p was consumed by an input method&quot;, event);
+        return YES;
+    }
+
+    LOG(TextInput, &quot;...interpretKeyEvents for event %p done, returns %d&quot;, event, parameters.eventInterpretationHadSideEffects);
+
+    // If we have already executed all or some of the commands, the event is &quot;handled&quot;. Note that there are additional checks on web process side.
+    return parameters.eventInterpretationHadSideEffects;
+}
+
+void WebViewImpl::executeSavedKeypressCommands()
+{
+    auto* parameters = m_interpretKeyEventsParameters;
+    if (!parameters || parameters-&gt;commands-&gt;isEmpty())
+        return;
+
+    // We could be called again if the execution of one command triggers a call to selectedRange.
+    // In this case, the state is up to date, and we don't need to execute any more saved commands to return a result.
+    if (parameters-&gt;executingSavedKeypressCommands)
+        return;
+
+    LOG(TextInput, &quot;Executing %u saved keypress commands...&quot;, parameters-&gt;commands-&gt;size());
+
+    parameters-&gt;executingSavedKeypressCommands = true;
+    parameters-&gt;eventInterpretationHadSideEffects |= m_page.executeKeypressCommands(*parameters-&gt;commands);
+    parameters-&gt;commands-&gt;clear();
+    parameters-&gt;executingSavedKeypressCommands = false;
+
+    LOG(TextInput, &quot;...done executing saved keypress commands.&quot;);
+}
+
+void WebViewImpl::doCommandBySelector(SEL selector)
+{
+    LOG(TextInput, &quot;doCommandBySelector:\&quot;%s\&quot;&quot;, sel_getName(selector));
+
+    auto* parameters = m_interpretKeyEventsParameters;
+    if (parameters)
+        parameters-&gt;consumedByIM = false;
+
+    // As in insertText:replacementRange:, we assume that the call comes from an input method if there is marked text.
+    bool isFromInputMethod = m_page.editorState().hasComposition;
+
+    if (parameters &amp;&amp; !isFromInputMethod) {
+        WebCore::KeypressCommand command(NSStringFromSelector(selector));
+        parameters-&gt;commands-&gt;append(command);
+        LOG(TextInput, &quot;...stored&quot;);
+        m_page.registerKeypressCommandName(command.commandName);
+    } else {
+        // FIXME: Send the command to Editor synchronously and only send it along the
+        // responder chain if it's a selector that does not correspond to an editing command.
+        [m_view _superDoCommandBySelector:selector];
+    }
+}
+
+void WebViewImpl::insertText(id string)
+{
+    // Unlike an NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
+    // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
+    // command ensures that a keypress event is dispatched as appropriate.
+    insertText(string, NSMakeRange(NSNotFound, 0));
+}
+
+void WebViewImpl::insertText(id string, NSRange replacementRange)
+{
+    bool isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
+    if (replacementRange.location != NSNotFound)
+        LOG(TextInput, &quot;insertText:\&quot;%@\&quot; replacementRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
+    else
+        LOG(TextInput, &quot;insertText:\&quot;%@\&quot;&quot;, isAttributedString ? [string string] : string);
+    auto* parameters = m_interpretKeyEventsParameters;
+    if (parameters)
+        parameters-&gt;consumedByIM = false;
+
+    NSString *text;
+    bool isFromInputMethod = m_page.editorState().hasComposition;
+
+    Vector&lt;WebCore::TextAlternativeWithRange&gt; dictationAlternatives;
+
+    if (isAttributedString) {
+#if USE(DICTATION_ALTERNATIVES)
+        WebCore::collectDictationTextAlternatives(string, dictationAlternatives);
+#endif
+        // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
+        text = [string string];
+    } else
+        text = string;
+
+    // insertText can be called for several reasons:
+    // - If it's from normal key event processing (including key bindings), we may need to save the action to perform it later.
+    // - If it's from an input method, then we should insert the text now. We assume it's from the input method if we have marked text.
+    // FIXME: In theory, this could be wrong for some input methods, so we should try to find another way to determine if the call is from the input method.
+    // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
+    // then we also execute it immediately, as there will be no other chance.
+    if (parameters &amp;&amp; !isFromInputMethod) {
+        // FIXME: Handle replacementRange in this case, too. It's known to occur in practice when canceling Press and Hold (see &lt;rdar://11940670&gt;).
+        ASSERT(replacementRange.location == NSNotFound);
+        WebCore::KeypressCommand command(&quot;insertText:&quot;, text);
+        parameters-&gt;commands-&gt;append(command);
+        m_page.registerKeypressCommandName(command.commandName);
+        return;
+    }
+
+    String eventText = text;
+    eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
+    bool eventHandled;
+    if (!dictationAlternatives.isEmpty())
+        eventHandled = m_page.insertDictatedText(eventText, replacementRange, dictationAlternatives);
+    else
+        eventHandled = m_page.insertText(eventText, replacementRange);
+
+    if (parameters)
+        parameters-&gt;eventInterpretationHadSideEffects |= eventHandled;
+}
+
+NSTextInputContext *WebViewImpl::inputContext()
+{
+    auto* parameters = m_interpretKeyEventsParameters;
+
+    if (pluginComplexTextInputIdentifier() &amp;&amp; !parameters)
+        return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
+
+    // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
+    if (!m_page.editorState().isContentEditable)
+        return nil;
+
+    return [m_view _superInputContext];
+}
+
+NSRange WebViewImpl::selectedRange()
+{
+    executeSavedKeypressCommands();
+
+    EditingRange selectedRange;
+    m_page.getSelectedRange(selectedRange);
+
+    NSRange result = selectedRange;
+    if (result.location == NSNotFound)
+        LOG(TextInput, &quot;selectedRange -&gt; (NSNotFound, %u)&quot;, result.length);
+    else
+        LOG(TextInput, &quot;selectedRange -&gt; (%u, %u)&quot;, result.location, result.length);
+
+    return result;
+}
+
+bool WebViewImpl::hasMarkedText()
+{
+    auto* parameters = m_interpretKeyEventsParameters;
+
+    BOOL result;
+    if (parameters) {
+        result = m_page.editorState().hasComposition;
+        if (result) {
+            // A saved command can confirm a composition, but it cannot start a new one.
+            executeSavedKeypressCommands();
+            result = m_page.editorState().hasComposition;
+        }
+    } else {
+        EditingRange markedRange;
+        m_page.getMarkedRange(markedRange);
+        result = markedRange.location != notFound;
+    }
+
+    LOG(TextInput, &quot;hasMarkedText -&gt; %u&quot;, result);
+    return result;
+}
+
+void WebViewImpl::unmarkText()
+{
+    executeSavedKeypressCommands();
+
+    LOG(TextInput, &quot;unmarkText&quot;);
+
+    auto* parameters = m_interpretKeyEventsParameters;
+
+    if (parameters) {
+        parameters-&gt;eventInterpretationHadSideEffects = true;
+        parameters-&gt;consumedByIM = false;
+    }
+
+    m_page.confirmComposition();
+}
+
+void WebViewImpl::setMarkedText(id string, NSRange newSelectedRange, NSRange replacementRange)
+{
+    executeSavedKeypressCommands();
+
+    BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+    ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
+    LOG(TextInput, &quot;setMarkedText:\&quot;%@\&quot; selectedRange:(%u, %u)&quot;, isAttributedString ? [string string] : string, newSelectedRange.location, newSelectedRange.length);
+
+    auto* parameters = m_interpretKeyEventsParameters;
+
+    if (parameters) {
+        parameters-&gt;eventInterpretationHadSideEffects = true;
+        parameters-&gt;consumedByIM = false;
+    }
+    
+    Vector&lt;WebCore::CompositionUnderline&gt; underlines;
+    NSString *text;
+
+    if (isAttributedString) {
+        // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
+        text = [string string];
+        underlines = extractUnderlines(string);
+    } else
+        text = string;
+
+    if (m_page.editorState().isInPasswordField) {
+        // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
+        // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
+        ASSERT(!m_page.editorState().hasComposition);
+        notifyInputContextAboutDiscardedComposition();
+        if ([text length] == 1 &amp;&amp; [[text decomposedStringWithCanonicalMapping] characterAtIndex:0] &lt; 0x80) {
+            m_page.insertText(text, replacementRange);
+        } else
+            NSBeep();
+        return;
+    }
+
+    m_page.setComposition(text, underlines, newSelectedRange, replacementRange);
+}
+
+NSRange WebViewImpl::markedRange()
+{
+    executeSavedKeypressCommands();
+
+    EditingRange markedRange;
+    m_page.getMarkedRange(markedRange);
+
+    NSRange result = markedRange;
+    if (result.location == NSNotFound)
+        LOG(TextInput, &quot;markedRange -&gt; (NSNotFound, %u)&quot;, result.length);
+    else
+        LOG(TextInput, &quot;markedRange -&gt; (%u, %u)&quot;, result.location, result.length);
+
+    return result;
+}
+
+NSAttributedString *WebViewImpl::attributedSubstringForProposedRange(NSRange proposedRange, NSRangePointer actualRange)
+{
+    executeSavedKeypressCommands();
+
+    if (!m_page.editorState().isContentEditable) {
+        LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u) -&gt; nil&quot;, proposedRange.location, proposedRange.length);
+        return nil;
+    }
+
+    if (m_page.editorState().isInPasswordField)
+        return nil;
+
+    AttributedString result;
+    m_page.getAttributedSubstringFromRange(proposedRange, result);
+
+    if (actualRange) {
+        *actualRange = proposedRange;
+        actualRange-&gt;length = [result.string length];
+    }
+
+    LOG(TextInput, &quot;attributedSubstringFromRange:(%u, %u) -&gt; \&quot;%@\&quot;&quot;, proposedRange.location, proposedRange.length, [result.string string]);
+    return [[result.string retain] autorelease];
+}
+
+NSUInteger WebViewImpl::characterIndexForPoint(NSPoint point)
+{
+    executeSavedKeypressCommands();
+
+    NSWindow *window = m_view.window;
+    
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored &quot;-Wdeprecated-declarations&quot;
+    if (window)
+        point = [window convertScreenToBase:point];
+#pragma clang diagnostic pop
+    point = [m_view convertPoint:point fromView:nil];  // the point is relative to the main frame
+    
+    uint64_t result = m_page.characterIndexForPoint(WebCore::IntPoint(point));
+    if (result == notFound)
+        result = NSNotFound;
+    LOG(TextInput, &quot;characterIndexForPoint:(%f, %f) -&gt; %u&quot;, point.x, point.y, result);
+    return result;
+}
+
+NSRect WebViewImpl::firstRectForCharacterRange(NSRange range, NSRangePointer actualRange)
+{
+    executeSavedKeypressCommands();
+
+    // Just to match NSTextView's behavior. Regression tests cannot detect this;
+    // to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
+    // (type something; try ranges (1, -1) and (2, -1).
+    if ((range.location + range.length &lt; range.location) &amp;&amp; (range.location + range.length != 0))
+        range.length = 0;
+
+    if (range.location == NSNotFound) {
+        if (actualRange)
+            *actualRange = range;
+        LOG(TextInput, &quot;firstRectForCharacterRange:(NSNotFound, %u) -&gt; NSZeroRect&quot;, range.length);
+        return NSZeroRect;
+    }
+
+    NSRect resultRect = m_page.firstRectForCharacterRange(range);
+    resultRect = [m_view convertRect:resultRect toView:nil];
+    resultRect = [m_view.window convertRectToScreen:resultRect];
+
+    if (actualRange) {
+        // FIXME: Update actualRange to match the range of first rect.
+        *actualRange = range;
+    }
+
+    LOG(TextInput, &quot;firstRectForCharacterRange:(%u, %u) -&gt; (%f, %f, %f, %f)&quot;, range.location, range.length, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
+    return resultRect;
+}
+
+bool WebViewImpl::performKeyEquivalent(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return false;
+
+    // There's a chance that responding to this event will run a nested event loop, and
+    // fetching a new event might release the old one. Retaining and then autoreleasing
+    // the current event prevents that from causing a problem inside WebKit or AppKit code.
+    [[event retain] autorelease];
+
+    // We get Esc key here after processing either Esc or Cmd+period. The former starts as a keyDown, and the latter starts as a key equivalent,
+    // but both get transformed to a cancelOperation: command, executing which passes an Esc key event to -performKeyEquivalent:.
+    // Don't interpret this event again, avoiding re-entrancy and infinite loops.
+    if ([[event charactersIgnoringModifiers] isEqualToString:@&quot;\e&quot;] &amp;&amp; !([event modifierFlags] &amp; NSDeviceIndependentModifierFlagsMask))
+        return [m_view _superPerformKeyEquivalent:event];
+
+    if (m_keyDownEventBeingResent) {
+        // WebCore has already seen the event, no need for custom processing.
+        // Note that we can get multiple events for each event being re-sent. For example, for Cmd+'=' AppKit
+        // first performs the original key equivalent, and if that isn't handled, it dispatches a synthetic Cmd+'+'.
+        return [m_view _superPerformKeyEquivalent:event];
+    }
+
+    ASSERT(event == [NSApp currentEvent]);
+
+    disableComplexTextInputIfNecessary();
+
+    // Pass key combos through WebCore if there is a key binding available for
+    // this event. This lets webpages have a crack at intercepting key-modified keypresses.
+    // FIXME: Why is the firstResponder check needed?
+    if (m_view == m_view.window.firstResponder) {
+        Vector&lt;WebCore::KeypressCommand&gt; commands;
+        bool handledByInputMethod = interpretKeyEvent(event, commands);
+        m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+        return true;
+    }
+    
+    return [m_view _superPerformKeyEquivalent:event];
+}
+
+void WebViewImpl::keyUp(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;keyUp:%p %@&quot;, event, event);
+    // We don't interpret the keyUp event, as this breaks key bindings (see &lt;https://bugs.webkit.org/show_bug.cgi?id=130100&gt;).
+    m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, false, { }));
+}
+
+void WebViewImpl::keyDown(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;keyDown:%p %@%s&quot;, event, event, (event == m_keyDownEventBeingResent) ? &quot; (re-sent)&quot; : &quot;&quot;);
+
+    // There's a chance that responding to this event will run a nested event loop, and
+    // fetching a new event might release the old one. Retaining and then autoreleasing
+    // the current event prevents that from causing a problem inside WebKit or AppKit code.
+    [[event retain] autorelease];
+
+    if (tryHandlePluginComplexTextInputKeyDown(event)) {
+        LOG(TextInput, &quot;...handled by plug-in&quot;);
+        return;
+    }
+
+    // We could be receiving a key down from AppKit if we have re-sent an event
+    // that maps to an action that is currently unavailable (for example a copy when
+    // there is no range selection).
+    // If this is the case we should ignore the key down.
+    if (m_keyDownEventBeingResent == event) {
+        [m_view _superKeyDown:event];
+        return;
+    }
+
+    Vector&lt;WebCore::KeypressCommand&gt; commands;
+    bool handledByInputMethod = interpretKeyEvent(event, commands);
+    if (!commands.isEmpty()) {
+        // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
+        // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
+        // should be handled like normal text input after DOM event dispatch.
+        handledByInputMethod = false;
+    }
+
+    m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, commands));
+}
+
+void WebViewImpl::flagsChanged(NSEvent *event)
+{
+    if (ignoresNonWheelEvents())
+        return;
+
+    LOG(TextInput, &quot;flagsChanged:%p %@&quot;, event, event);
+
+    // There's a chance that responding to this event will run a nested event loop, and
+    // fetching a new event might release the old one. Retaining and then autoreleasing
+    // the current event prevents that from causing a problem inside WebKit or AppKit code.
+    [[event retain] autorelease];
+
+    // Don't make an event from the num lock and function keys
+    if (eventKeyCodeIsZeroOrNumLockOrFn(event))
+        return;
+
+    m_page.handleKeyboardEvent(NativeWebKeyboardEvent(event, false, { }));
+}
+
+#endif // USE(ASYNC_NSTEXTINPUTCLIENT)
+
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #endif // PLATFORM(MAC)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessmacPageClientImplmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm (191790 => 191791)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm        2015-10-30 16:51:19 UTC (rev 191790)
+++ trunk/Source/WebKit2/UIProcess/mac/PageClientImpl.mm        2015-10-30 17:02:36 UTC (rev 191791)
</span><span class="lines">@@ -435,7 +435,7 @@
</span><span class="cx"> 
</span><span class="cx"> void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent&amp; event, bool eventWasHandled)
</span><span class="cx"> {
</span><del>-    [m_wkView _doneWithKeyEvent:event.nativeEvent() eventWasHandled:eventWasHandled];
</del><ins>+    m_impl-&gt;doneWithKeyEvent(event.nativeEvent(), eventWasHandled);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RefPtr&lt;WebPopupMenuProxy&gt; PageClientImpl::createPopupMenuProxy(WebPageProxy&amp; page)
</span></span></pre>
</div>
</div>

</body>
</html>