<!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>[166002] 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/166002">166002</a></dd>
<dt>Author</dt> <dd>ap@apple.com</dd>
<dt>Date</dt> <dd>2014-03-20 14:17:51 -0700 (Thu, 20 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Update iOS input method code to use new cross-platform async functions
https://bugs.webkit.org/show_bug.cgi?id=130530

Reviewed by Enrica Casucci.

Merge identical iOS and cross-platform functions.

Also tightened up ifdefs, and removed stub iOS implementations of sync methods,
which hopefully won't be ever needed. The only tricky case is sync cancelComposition,
will I'll investigate separately.

* UIProcess/WebPageProxy.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setMarkedText:selectedRange:]):
(-[WKContentView unmarkText]):
(-[WKContentView insertText:]):
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::cancelComposition):
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::cancelComposition):
(WebKit::WebPageProxy::insertDictatedTextAsync):
(WebKit::WebPageProxy::attributedSubstringForCharacterRangeAsync):
(WebKit::WebPageProxy::attributedStringForCharacterRangeCallback):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::cancelComposition):
(WebKit::WebPage::insertDictatedTextAsync):
(WebKit::WebPage::attributedSubstringForCharacterRangeAsync):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxyh">trunk/Source/WebKit2/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm">trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessmacWebPageProxyMacmm">trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPageh">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagemessagesin">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageiosWebPageIOSmm">trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPagemacWebPageMacmm">trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/ChangeLog        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -1,5 +1,38 @@
</span><span class="cx"> 2014-03-20  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Update iOS input method code to use new cross-platform async functions
+        https://bugs.webkit.org/show_bug.cgi?id=130530
+
+        Reviewed by Enrica Casucci.
+
+        Merge identical iOS and cross-platform functions.
+
+        Also tightened up ifdefs, and removed stub iOS implementations of sync methods,
+        which hopefully won't be ever needed. The only tricky case is sync cancelComposition,
+        will I'll investigate separately.
+
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView setMarkedText:selectedRange:]):
+        (-[WKContentView unmarkText]):
+        (-[WKContentView insertText:]):
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::cancelComposition):
+        * UIProcess/mac/WebPageProxyMac.mm:
+        (WebKit::WebPageProxy::cancelComposition):
+        (WebKit::WebPageProxy::insertDictatedTextAsync):
+        (WebKit::WebPageProxy::attributedSubstringForCharacterRangeAsync):
+        (WebKit::WebPageProxy::attributedStringForCharacterRangeCallback):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::cancelComposition):
+        (WebKit::WebPage::insertDictatedTextAsync):
+        (WebKit::WebPage::attributedSubstringForCharacterRangeAsync):
+
+2014-03-20  Alexey Proskuryakov  &lt;ap@apple.com&gt;
+
</ins><span class="cx">         ASSERTION FAILED: event == [NSApp currentEvent] hitting Command-+
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=130526
</span><span class="cx">         &lt;rdar://problem/16371612&gt;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -628,16 +628,6 @@
</span><span class="cx">     void windowAndViewFramesChanged(const WebCore::FloatRect&amp; viewFrameInWindowCoordinates, const WebCore::FloatPoint&amp; accessibilityViewCoordinates);
</span><span class="cx">     void setMainFrameIsScrollable(bool);
</span><span class="cx"> 
</span><del>-    void setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange);
-    void confirmComposition();
-    void cancelComposition();
-    bool insertText(const String&amp; text, const EditingRange&amp; replacementRange);
-    void getMarkedRange(EditingRange&amp;);
-    void getSelectedRange(EditingRange&amp;);
-    uint64_t characterIndexForPoint(const WebCore::IntPoint);
-    WebCore::IntRect firstRectForCharacterRange(const EditingRange&amp;);
-    bool executeKeypressCommands(const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
-
</del><span class="cx">     void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String&amp; textInput);
</span><span class="cx">     bool shouldDelayWindowOrderingForEvent(const WebMouseEvent&amp;);
</span><span class="cx">     bool acceptsFirstMouse(int eventNumber, const WebMouseEvent&amp;);
</span><span class="lines">@@ -653,12 +643,25 @@
</span><span class="cx">     void setCompositionAsync(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange);
</span><span class="cx">     void confirmCompositionAsync();
</span><span class="cx"> 
</span><ins>+    void cancelComposition();
+
</ins><span class="cx"> #if PLATFORM(MAC)
</span><del>-    bool insertDictatedText(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::TextAlternativeWithRange&gt;&amp; dictationAlternatives);
</del><span class="cx">     void insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::TextAlternativeWithRange&gt;&amp; dictationAlternatives);
</span><del>-    void getAttributedSubstringFromRange(const EditingRange&amp;, AttributedString&amp;);
</del><span class="cx">     void attributedSubstringForCharacterRangeAsync(const EditingRange&amp;, PassRefPtr&lt;AttributedStringForCharacterRangeCallback&gt;);
</span><span class="cx"> 
</span><ins>+#if !USE(ASYNC_NSTEXTINPUTCLIENT)
+    bool insertText(const String&amp; text, const EditingRange&amp; replacementRange);
+    void setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange);
+    void confirmComposition();
+    bool insertDictatedText(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::TextAlternativeWithRange&gt;&amp; dictationAlternatives);
+    void getAttributedSubstringFromRange(const EditingRange&amp;, AttributedString&amp;);
+    void getMarkedRange(EditingRange&amp;);
+    void getSelectedRange(EditingRange&amp;);
+    uint64_t characterIndexForPoint(const WebCore::IntPoint);
+    WebCore::IntRect firstRectForCharacterRange(const EditingRange&amp;);
+    bool executeKeypressCommands(const Vector&lt;WebCore::KeypressCommand&gt;&amp;);
+#endif
+
</ins><span class="cx">     WKView* wkView() const;
</span><span class="cx">     void intrinsicContentSizeDidChange(const WebCore::IntSize&amp; intrinsicContentSize);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -1410,13 +1410,13 @@
</span><span class="cx"> - (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
</span><span class="cx"> {
</span><span class="cx">     _markedText = markedText;
</span><del>-    _page-&gt;setComposition(markedText, Vector&lt;WebCore::CompositionUnderline&gt;(), selectedRange, EditingRange());
</del><ins>+    _page-&gt;setCompositionAsync(markedText, Vector&lt;WebCore::CompositionUnderline&gt;(), selectedRange, EditingRange());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)unmarkText
</span><span class="cx"> {
</span><span class="cx">     _markedText = nil;
</span><del>-    _page-&gt;confirmComposition();
</del><ins>+    _page-&gt;confirmCompositionAsync();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (UITextPosition *)beginningOfDocument
</span><span class="lines">@@ -1507,7 +1507,7 @@
</span><span class="cx"> // Inserts the given string, replacing any selected or marked text.
</span><span class="cx"> - (void)insertText:(NSString *)aStringValue
</span><span class="cx"> {
</span><del>-    _page-&gt;insertText(aStringValue, EditingRange());
</del><ins>+    _page-&gt;insertTextAsync(aStringValue, EditingRange());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)hasText
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -99,65 +99,11 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPageProxy::setComposition(const String&amp; text, Vector&lt;CompositionUnderline&gt; underline, const EditingRange&amp; selectionRange, const EditingRange&amp;)
-{
-    if (!isValid())
-        return;
-
-    process().send(Messages::WebPage::SetComposition(text, underline, selectionRange), m_pageID);
-}
-
-void WebPageProxy::confirmComposition()
-{
-    if (!isValid())
-        return;
-
-    process().send(Messages::WebPage::ConfirmComposition(), m_pageID);
-}
-
</del><span class="cx"> void WebPageProxy::cancelComposition()
</span><span class="cx"> {
</span><span class="cx">     notImplemented();
</span><del>-
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool WebPageProxy::insertText(const String&amp; text, const EditingRange&amp; replacementRange)
-{
-    if (!isValid())
-        return true;
-    
-    process().send(Messages::WebPage::InsertText(text, replacementRange), m_pageID);
-    return true;
-}
-
-void WebPageProxy::getMarkedRange(EditingRange&amp;)
-{
-    notImplemented();
-}
-
-void WebPageProxy::getSelectedRange(EditingRange&amp;)
-{
-    notImplemented();
-}
-
-uint64_t WebPageProxy::characterIndexForPoint(const IntPoint)
-{
-    notImplemented();
-    return 0;
-}
-
-IntRect WebPageProxy::firstRectForCharacterRange(const EditingRange&amp;)
-{
-    notImplemented();
-    return IntRect();
-}
-
-bool WebPageProxy::executeKeypressCommands(const Vector&lt;WebCore::KeypressCommand&gt;&amp;)
-{
-    notImplemented();
-    return false;
-}
-
</del><span class="cx"> String WebPageProxy::stringSelectionForPasteboard()
</span><span class="cx"> {
</span><span class="cx">     notImplemented();
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessmacWebPageProxyMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -152,6 +152,8 @@
</span><span class="cx">     process().send(Messages::WebPage::SetMainFrameIsScrollable(isScrollable), m_pageID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if !USE(ASYNC_NSTEXTINPUTCLIENT)
+
</ins><span class="cx"> void WebPageProxy::setComposition(const String&amp; text, Vector&lt;CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange)
</span><span class="cx"> {
</span><span class="cx">     if (!isValid()) {
</span><span class="lines">@@ -171,14 +173,6 @@
</span><span class="cx">     process().sendSync(Messages::WebPage::ConfirmComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPageProxy::cancelComposition()
-{
-    if (!isValid())
-        return;
-
-    process().sendSync(Messages::WebPage::CancelComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
-}
-
</del><span class="cx"> bool WebPageProxy::insertText(const String&amp; text, const EditingRange&amp; replacementRange)
</span><span class="cx"> {
</span><span class="cx">     if (!isValid())
</span><span class="lines">@@ -220,31 +214,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPageProxy::insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;TextAlternativeWithRange&gt;&amp; dictationAlternativesWithRange)
-{
-#if USE(DICTATION_ALTERNATIVES)
-    if (!isValid())
-        return;
-
-    Vector&lt;DictationAlternative&gt; dictationAlternatives;
-
-    for (const TextAlternativeWithRange&amp; alternativeWithRange : dictationAlternativesWithRange) {
-        uint64_t dictationContext = m_pageClient.addDictationAlternatives(alternativeWithRange.alternatives);
-        if (dictationContext)
-            dictationAlternatives.append(DictationAlternative(alternativeWithRange.range.location, alternativeWithRange.range.length, dictationContext));
-    }
-
-    if (dictationAlternatives.isEmpty()) {
-        insertTextAsync(text, replacementRange);
-        return;
-    }
-
-    process().send(Messages::WebPage::InsertDictatedTextAsync(text, replacementRange, dictationAlternatives), m_pageID);
-#else
-    insertTextAsync(text, replacementRange);
-#endif
-}
-
</del><span class="cx"> void WebPageProxy::getMarkedRange(EditingRange&amp; result)
</span><span class="cx"> {
</span><span class="cx">     result = EditingRange();
</span><span class="lines">@@ -274,33 +243,6 @@
</span><span class="cx">     process().sendSync(Messages::WebPage::GetAttributedSubstringFromRange(range), Messages::WebPage::GetAttributedSubstringFromRange::Reply(result), m_pageID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPageProxy::attributedSubstringForCharacterRangeAsync(const EditingRange&amp; range, PassRefPtr&lt;AttributedStringForCharacterRangeCallback&gt; callback)
-{
-    if (!isValid()) {
-        callback-&gt;invalidate();
-        return;
-    }
-
-    uint64_t callbackID = callback-&gt;callbackID();
-    m_attributedStringForCharacterRangeCallbacks.set(callbackID, callback);
-
-    process().send(Messages::WebPage::AttributedSubstringForCharacterRangeAsync(range, callbackID), m_pageID);
-}
-
-void WebPageProxy::attributedStringForCharacterRangeCallback(const AttributedString&amp; string, const EditingRange&amp; actualRange, uint64_t callbackID)
-{
-    MESSAGE_CHECK(actualRange.isValid());
-
-    RefPtr&lt;AttributedStringForCharacterRangeCallback&gt; callback = m_attributedStringForCharacterRangeCallbacks.take(callbackID);
-    if (!callback) {
-        // FIXME: Log error or assert.
-        // this can validly happen if a load invalidated the callback, though
-        return;
-    }
-
-    callback-&gt;performCallbackWithReturnValue(string, actualRange);
-}
-
</del><span class="cx"> uint64_t WebPageProxy::characterIndexForPoint(const IntPoint point)
</span><span class="cx"> {
</span><span class="cx">     if (!isValid())
</span><span class="lines">@@ -331,6 +273,68 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#endif // !USE(ASYNC_NSTEXTINPUTCLIENT)
+
+void WebPageProxy::cancelComposition()
+{
+    if (!isValid())
+        return;
+
+    process().sendSync(Messages::WebPage::CancelComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
+}
+
+void WebPageProxy::insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;TextAlternativeWithRange&gt;&amp; dictationAlternativesWithRange)
+{
+#if USE(DICTATION_ALTERNATIVES)
+    if (!isValid())
+        return;
+
+    Vector&lt;DictationAlternative&gt; dictationAlternatives;
+
+    for (const TextAlternativeWithRange&amp; alternativeWithRange : dictationAlternativesWithRange) {
+        uint64_t dictationContext = m_pageClient.addDictationAlternatives(alternativeWithRange.alternatives);
+        if (dictationContext)
+            dictationAlternatives.append(DictationAlternative(alternativeWithRange.range.location, alternativeWithRange.range.length, dictationContext));
+    }
+
+    if (dictationAlternatives.isEmpty()) {
+        insertTextAsync(text, replacementRange);
+        return;
+    }
+
+    process().send(Messages::WebPage::InsertDictatedTextAsync(text, replacementRange, dictationAlternatives), m_pageID);
+#else
+    insertTextAsync(text, replacementRange);
+#endif
+}
+
+void WebPageProxy::attributedSubstringForCharacterRangeAsync(const EditingRange&amp; range, PassRefPtr&lt;AttributedStringForCharacterRangeCallback&gt; callback)
+{
+    if (!isValid()) {
+        callback-&gt;invalidate();
+        return;
+    }
+
+    uint64_t callbackID = callback-&gt;callbackID();
+    m_attributedStringForCharacterRangeCallbacks.set(callbackID, callback);
+
+    process().send(Messages::WebPage::AttributedSubstringForCharacterRangeAsync(range, callbackID), m_pageID);
+}
+
+void WebPageProxy::attributedStringForCharacterRangeCallback(const AttributedString&amp; string, const EditingRange&amp; actualRange, uint64_t callbackID)
+{
+    MESSAGE_CHECK(actualRange.isValid());
+
+    RefPtr&lt;AttributedStringForCharacterRangeCallback&gt; callback = m_attributedStringForCharacterRangeCallbacks.take(callbackID);
+    if (!callback) {
+        // FIXME: Log error or assert.
+        // this can validly happen if a load invalidated the callback, though
+        return;
+    }
+
+    callback-&gt;performCallbackWithReturnValue(string, actualRange);
+}
+
</ins><span class="cx"> String WebPageProxy::stringSelectionForPasteboard()
</span><span class="cx"> {
</span><span class="cx">     String value;
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -457,9 +457,6 @@
</span><span class="cx">     void syncApplyAutocorrection(const String&amp; correction, const String&amp; originalText, bool&amp; correctionApplied);
</span><span class="cx">     void requestAutocorrectionContext(uint64_t callbackID);
</span><span class="cx">     void getAutocorrectionContext(String&amp; beforeText, String&amp; markedText, String&amp; selectedText, String&amp; afterText, uint64_t&amp; location, uint64_t&amp; length);
</span><del>-    void insertText(const String&amp; text, const EditingRange&amp; replacementRange);
-    void setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange);
-    void confirmComposition();
</del><span class="cx">     void getPositionInformation(const WebCore::IntPoint&amp;, InteractionInformationAtPosition&amp;);
</span><span class="cx">     void requestPositionInformation(const WebCore::IntPoint&amp;);
</span><span class="cx">     void startInteractionWithElementAtPosition(const WebCore::IntPoint&amp;);
</span><span class="lines">@@ -538,16 +535,6 @@
</span><span class="cx">     
</span><span class="cx">     void sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String&amp; textInput);
</span><span class="cx"> 
</span><del>-#if PLATFORM(MAC)
-    void insertText(const String&amp; text, const EditingRange&amp; replacementRange, bool&amp; handled, EditorState&amp; newState);
-    void setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange, EditorState&amp; newState);
-    void confirmComposition(EditorState&amp; newState);
-    void insertDictatedText(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations, bool&amp; handled, EditorState&amp; newState);
-    void insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations);
-    void getAttributedSubstringFromRange(const EditingRange&amp;, AttributedString&amp;);
-    void attributedSubstringForCharacterRangeAsync(const EditingRange&amp;, uint64_t callbackID);
-#endif
-
</del><span class="cx">     void insertTextAsync(const String&amp; text, const EditingRange&amp; replacementRange);
</span><span class="cx">     void getMarkedRangeAsync(uint64_t callbackID);
</span><span class="cx">     void getSelectedRangeAsync(uint64_t callbackID);
</span><span class="lines">@@ -556,12 +543,24 @@
</span><span class="cx">     void setCompositionAsync(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange);
</span><span class="cx">     void confirmCompositionAsync();
</span><span class="cx"> 
</span><ins>+#if PLATFORM(MAC)
</ins><span class="cx">     void cancelComposition(EditorState&amp; newState);
</span><ins>+    void insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations);
+    void attributedSubstringForCharacterRangeAsync(const EditingRange&amp;, uint64_t callbackID);
+#if !USE(ASYNC_NSTEXTINPUTCLIENT)
+    void insertText(const String&amp; text, const EditingRange&amp; replacementRange, bool&amp; handled, EditorState&amp; newState);
+    void setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementRange, EditorState&amp; newState);
+    void confirmComposition(EditorState&amp; newState);
+    void insertDictatedText(const String&amp; text, const EditingRange&amp; replacementRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations, bool&amp; handled, EditorState&amp; newState);
+    void getAttributedSubstringFromRange(const EditingRange&amp;, AttributedString&amp;);
</ins><span class="cx">     void getMarkedRange(EditingRange&amp;);
</span><span class="cx">     void getSelectedRange(EditingRange&amp;);
</span><span class="cx">     void characterIndexForPoint(const WebCore::IntPoint point, uint64_t&amp; result);
</span><span class="cx">     void firstRectForCharacterRange(const EditingRange&amp;, WebCore::IntRect&amp; resultRect);
</span><span class="cx">     void executeKeypressCommands(const Vector&lt;WebCore::KeypressCommand&gt;&amp;, bool&amp; handled, EditorState&amp; newState);
</span><ins>+#endif
+#endif
+
</ins><span class="cx">     void readSelectionFromPasteboard(const WTF::String&amp; pasteboardName, bool&amp; result);
</span><span class="cx">     void getStringSelectionForPasteboard(WTF::String&amp; stringValue);
</span><span class="cx">     void getDataSelectionForPasteboard(const WTF::String pasteboardType, SharedMemory::Handle&amp; handle, uint64_t&amp; size);
</span><span class="lines">@@ -787,7 +786,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     bool performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&amp;);
</span><span class="cx"> 
</span><del>-#if PLATFORM(COCOA)
</del><ins>+#if PLATFORM(MAC)
</ins><span class="cx">     bool executeKeypressCommandsInternal(const Vector&lt;WebCore::KeypressCommand&gt;&amp;, WebCore::KeyboardEvent*);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagemessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -56,10 +56,6 @@
</span><span class="cx">     SyncApplyAutocorrection(String correction, String originalText) -&gt; (bool autocorrectionApplied)
</span><span class="cx">     RequestAutocorrectionContext(uint64_t callbackID)
</span><span class="cx">     GetAutocorrectionContext() -&gt; (String beforeContext, String markedText, String selectedText, String afterContext, uint64_t location, uint64_t length) 
</span><del>-    # FIXME: Use shared COCOA text input methods like insertTextAsync.
-    InsertText(String text, WebKit::EditingRange replacementRange)
-    SetComposition(String text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, WebKit::EditingRange selectionRange)
-    ConfirmComposition()
</del><span class="cx">     GetPositionInformation(WebCore::IntPoint point) -&gt; (WebKit::InteractionInformationAtPosition information)
</span><span class="cx">     RequestPositionInformation(WebCore::IntPoint point)
</span><span class="cx">     StartInteractionWithElementAtPosition(WebCore::IntPoint point)
</span><span class="lines">@@ -295,13 +291,6 @@
</span><span class="cx">     GetDataSelectionForPasteboard(String pasteboardType) -&gt; (WebKit::SharedMemory::Handle handle, uint64_t size)
</span><span class="cx">     ReadSelectionFromPasteboard(String pasteboardName) -&gt; (bool result)
</span><span class="cx"> 
</span><del>-    # Text input.
-    CancelComposition() -&gt; (WebKit::EditorState newState)
-    GetMarkedRange() -&gt; (WebKit::EditingRange range)
-    GetSelectedRange() -&gt; (WebKit::EditingRange range)
-    CharacterIndexForPoint(WebCore::IntPoint point) -&gt; (uint64_t result)
-    FirstRectForCharacterRange(WebKit::EditingRange range) -&gt; (WebCore::IntRect resultRect)
-    ExecuteKeypressCommands(Vector&lt;WebCore::KeypressCommand&gt; savedCommands) -&gt; (bool handled, WebKit::EditorState newState)
</del><span class="cx">     ShouldDelayWindowOrderingEvent(WebKit::WebMouseEvent event) -&gt; (bool result)
</span><span class="cx">     AcceptsFirstMouse(int eventNumber, WebKit::WebMouseEvent event) -&gt; (bool result)
</span><span class="cx"> 
</span><span class="lines">@@ -314,14 +303,23 @@
</span><span class="cx">     ConfirmCompositionAsync()
</span><span class="cx"> #endif
</span><span class="cx"> #if PLATFORM(MAC)
</span><ins>+    CancelComposition() -&gt; (WebKit::EditorState newState)
+    InsertDictatedTextAsync(String text, WebKit::EditingRange replacementRange, Vector&lt;WebCore::DictationAlternative&gt; dictationAlternatives)
+    AttributedSubstringForCharacterRangeAsync(WebKit::EditingRange range, uint64_t callbackID);
+#endif
+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     InsertText(String text, WebKit::EditingRange replacementRange) -&gt; (bool handled, WebKit::EditorState newState)
</span><span class="cx">     SetComposition(String text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, WebKit::EditingRange selectionRange, WebKit::EditingRange replacementRange) -&gt; (WebKit::EditorState newState)
</span><span class="cx">     ConfirmComposition() -&gt; (WebKit::EditorState newState)
</span><span class="cx">     InsertDictatedText(String text, WebKit::EditingRange replacementRange, Vector&lt;WebCore::DictationAlternative&gt; dictationAlternatives) -&gt; (bool handled, WebKit::EditorState newState)
</span><del>-    InsertDictatedTextAsync(String text, WebKit::EditingRange replacementRange, Vector&lt;WebCore::DictationAlternative&gt; dictationAlternatives)
</del><span class="cx">     GetAttributedSubstringFromRange(WebKit::EditingRange range) -&gt; (WebKit::AttributedString result)
</span><del>-    AttributedSubstringForCharacterRangeAsync(WebKit::EditingRange range, uint64_t callbackID);
</del><ins>+    GetMarkedRange() -&gt; (WebKit::EditingRange range)
+    GetSelectedRange() -&gt; (WebKit::EditingRange range)
+    CharacterIndexForPoint(WebCore::IntPoint point) -&gt; (uint64_t result)
+    FirstRectForCharacterRange(WebKit::EditingRange range) -&gt; (WebCore::IntRect resultRect)
+    ExecuteKeypressCommands(Vector&lt;WebCore::KeypressCommand&gt; savedCommands) -&gt; (bool handled, WebKit::EditorState newState)
</ins><span class="cx"> #endif
</span><ins>+
</ins><span class="cx">     SetMinimumLayoutSize(WebCore::IntSize minimumLayoutSize)
</span><span class="cx">     SetAutoSizingShouldExpandToViewHeight(bool shouldExpand)
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageiosWebPageIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -110,12 +110,6 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool WebPage::executeKeypressCommandsInternal(const Vector&lt;WebCore::KeypressCommand&gt;&amp;, KeyboardEvent*)
-{
-    notImplemented();
-    return false;
-}
-
</del><span class="cx"> FloatSize WebPage::viewportScreenSize() const
</span><span class="cx"> {
</span><span class="cx">     return m_viewportScreenSize;
</span><span class="lines">@@ -167,68 +161,6 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPage::setComposition(const String&amp; text, Vector&lt;WebCore::CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange)
-{
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-
-    if (frame.selection().selection().isContentEditable())
-        frame.editor().setComposition(text, underlines, selectionRange.location, selectionRange.location + selectionRange.length);
-}
-
-void WebPage::confirmComposition()
-{
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-    frame.editor().confirmComposition();
-}
-
-void WebPage::cancelComposition(EditorState&amp;)
-{
-    notImplemented();
-}
-
-void WebPage::insertText(const String&amp; text, const EditingRange&amp; replacementEditingRange)
-{
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-    
-    if (replacementEditingRange.location != notFound) {
-        RefPtr&lt;Range&gt; replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
-        if (replacementRange)
-            frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
-    }
-    
-    if (!frame.editor().hasComposition()) {
-        // An insertText: might be handled by other responders in the chain if we don't handle it.
-        // One example is space bar that results in scrolling down the page.
-        frame.editor().insertText(text, nullptr);
-    } else
-        frame.editor().confirmComposition(text);
-}
-
-void WebPage::getMarkedRange(EditingRange&amp;)
-{
-    notImplemented();
-}
-
-void WebPage::getSelectedRange(EditingRange&amp;)
-{
-    notImplemented();
-}
-
-void WebPage::characterIndexForPoint(IntPoint, uint64_t&amp;)
-{
-    notImplemented();
-}
-
-void WebPage::firstRectForCharacterRange(const EditingRange&amp;, WebCore::IntRect&amp;)
-{
-    notImplemented();
-}
-
-void WebPage::executeKeypressCommands(const Vector&lt;WebCore::KeypressCommand&gt;&amp;, bool&amp;, EditorState&amp;)
-{
-    notImplemented();
-}
-
</del><span class="cx"> void WebPage::performDictionaryLookupAtLocation(const FloatPoint&amp;)
</span><span class="cx"> {
</span><span class="cx">     notImplemented();
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPagemacWebPageMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm (166001 => 166002)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm        2014-03-20 21:15:23 UTC (rev 166001)
+++ trunk/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm        2014-03-20 21:17:51 UTC (rev 166002)
</span><span class="lines">@@ -246,6 +246,8 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if !USE(ASYNC_NSTEXTINPUTCLIENT)
+
</ins><span class="cx"> void WebPage::setComposition(const String&amp; text, Vector&lt;CompositionUnderline&gt; underlines, const EditingRange&amp; selectionRange, const EditingRange&amp; replacementEditingRange, EditorState&amp; newState)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="lines">@@ -270,13 +272,6 @@
</span><span class="cx">     newState = editorState();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPage::cancelComposition(EditorState&amp; newState)
-{
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-    frame.editor().cancelComposition();
-    newState = editorState();
-}
-
</del><span class="cx"> void WebPage::insertText(const String&amp; text, const EditingRange&amp; replacementEditingRange, bool&amp; handled, EditorState&amp; newState)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="lines">@@ -314,20 +309,6 @@
</span><span class="cx">     newState = editorState();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPage::insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementEditingRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations)
-{
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-
-    if (replacementEditingRange.location != notFound) {
-        RefPtr&lt;Range&gt; replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
-        if (replacementRange)
-            frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
-    }
-
-    ASSERT(!frame.editor().hasComposition());
-    frame.editor().insertDictatedText(text, dictationAlternativeLocations, nullptr);
-}
-
</del><span class="cx"> void WebPage::getMarkedRange(EditingRange&amp; result)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="lines">@@ -379,39 +360,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void WebPage::attributedSubstringForCharacterRangeAsync(const EditingRange&amp; editingRange, uint64_t callbackID)
-{
-    AttributedString result;
-
-    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
-
-    const VisibleSelection&amp; selection = frame.selection().selection();
-    if (selection.isNone() || !selection.isContentEditable() || selection.isInPasswordField()) {
-        send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
-        return;
-    }
-
-    RefPtr&lt;Range&gt; range = rangeFromEditingRange(frame, editingRange);
-    if (!range) {
-        send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
-        return;
-    }
-
-    result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
-    NSAttributedString* attributedString = result.string.get();
-    
-    // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing 
-    // whitespace at the end of the string which breaks the ATOK input method.  &lt;rdar://problem/5400551&gt;
-    // To work around this we truncate the resultant string to the correct length.
-    if ([attributedString length] &gt; editingRange.length) {
-        ASSERT([attributedString length] == editingRange.length + 1);
-        ASSERT([[attributedString string] characterAtIndex:editingRange.length] == '\n' || [[attributedString string] characterAtIndex:editingRange.length] == ' ');
-        result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, editingRange.length)];
-    }
-
-    send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(editingRange.location, [result.string length]), callbackID));
-}
-
</del><span class="cx"> void WebPage::characterIndexForPoint(IntPoint point, uint64_t&amp; index)
</span><span class="cx"> {
</span><span class="cx">     index = notFound;
</span><span class="lines">@@ -452,6 +400,62 @@
</span><span class="cx">     newState = editorState();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#endif // !USE(ASYNC_NSTEXTINPUTCLIENT)
+
+void WebPage::cancelComposition(EditorState&amp; newState)
+{
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+    frame.editor().cancelComposition();
+    newState = editorState();
+}
+
+void WebPage::insertDictatedTextAsync(const String&amp; text, const EditingRange&amp; replacementEditingRange, const Vector&lt;WebCore::DictationAlternative&gt;&amp; dictationAlternativeLocations)
+{
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+
+    if (replacementEditingRange.location != notFound) {
+        RefPtr&lt;Range&gt; replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
+        if (replacementRange)
+            frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
+    }
+
+    ASSERT(!frame.editor().hasComposition());
+    frame.editor().insertDictatedText(text, dictationAlternativeLocations, nullptr);
+}
+
+void WebPage::attributedSubstringForCharacterRangeAsync(const EditingRange&amp; editingRange, uint64_t callbackID)
+{
+    AttributedString result;
+
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+
+    const VisibleSelection&amp; selection = frame.selection().selection();
+    if (selection.isNone() || !selection.isContentEditable() || selection.isInPasswordField()) {
+        send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
+        return;
+    }
+
+    RefPtr&lt;Range&gt; range = rangeFromEditingRange(frame, editingRange);
+    if (!range) {
+        send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(), callbackID));
+        return;
+    }
+
+    result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
+    NSAttributedString* attributedString = result.string.get();
+    
+    // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing 
+    // whitespace at the end of the string which breaks the ATOK input method.  &lt;rdar://problem/5400551&gt;
+    // To work around this we truncate the resultant string to the correct length.
+    if ([attributedString length] &gt; editingRange.length) {
+        ASSERT([attributedString length] == editingRange.length + 1);
+        ASSERT([[attributedString string] characterAtIndex:editingRange.length] == '\n' || [[attributedString string] characterAtIndex:editingRange.length] == ' ');
+        result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, editingRange.length)];
+    }
+
+    send(Messages::WebPageProxy::AttributedStringForCharacterRangeCallback(result, EditingRange(editingRange.location, [result.string length]), callbackID));
+}
+
</ins><span class="cx"> static bool isPositionInRange(const VisiblePosition&amp; position, Range* range)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;Range&gt; positionRange = makeRange(position, position);
</span></span></pre>
</div>
</div>

</body>
</html>