<!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>[166421] 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/166421">166421</a></dd>
<dt>Author</dt> <dd>ap@apple.com</dd>
<dt>Date</dt> <dd>2014-03-28 12:11:18 -0700 (Fri, 28 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Eliminate a sync cancelComposition call in WebPageProxy::editorStateChanged
https://bugs.webkit.org/show_bug.cgi?id=130727

Reviewed by Enrica Casucci.

Added a separate CompositionWasCanceled IPC call, with which WebProcess can tell
UIProcess that it should notify an input method of canceled composition. There are
a lot of incorrect edge cases where we don't call it correctly, but this was true
in the old implementation too (for different edge cases).

This change only affects iOS and async NSTextInputClient code path on Mac. I don't
want to change sync NSTextInputClient code path unless absolutely necessary.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::WebPageProxy):
(WebKit::WebPageProxy::editorStateChanged):
(WebKit::WebPageProxy::compositionWasCanceled):
(WebKit::WebPageProxy::resetStateAfterProcessExited):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/mac/WebPageProxyMac.mm:
(WebKit::WebPageProxy::insertText):
(WebKit::WebPageProxy::executeKeypressCommands):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didChangeSelection):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxycpp">trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxyh">trunk/Source/WebKit2/UIProcess/WebPageProxy.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessWebPageProxymessagesin">trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in</a></li>
<li><a href="#trunkSourceWebKit2UIProcessmacWebPageProxyMacmm">trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagecpp">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/ChangeLog        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2014-03-28  Alexey Proskuryakov  &lt;ap@apple.com&gt;
+
+        Eliminate a sync cancelComposition call in WebPageProxy::editorStateChanged
+        https://bugs.webkit.org/show_bug.cgi?id=130727
+
+        Reviewed by Enrica Casucci.
+
+        Added a separate CompositionWasCanceled IPC call, with which WebProcess can tell
+        UIProcess that it should notify an input method of canceled composition. There are
+        a lot of incorrect edge cases where we don't call it correctly, but this was true
+        in the old implementation too (for different edge cases).
+
+        This change only affects iOS and async NSTextInputClient code path on Mac. I don't
+        want to change sync NSTextInputClient code path unless absolutely necessary.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::WebPageProxy):
+        (WebKit::WebPageProxy::editorStateChanged):
+        (WebKit::WebPageProxy::compositionWasCanceled):
+        (WebKit::WebPageProxy::resetStateAfterProcessExited):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/mac/WebPageProxyMac.mm:
+        (WebKit::WebPageProxy::insertText):
+        (WebKit::WebPageProxy::executeKeypressCommands):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::didChangeSelection):
+
</ins><span class="cx"> 2014-03-28  Mario Sanchez Prada  &lt;mario.prada@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] Running minibrowser with url crashes in debug build
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.cpp        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -268,7 +268,9 @@
</span><span class="cx">     , m_viewState(ViewState::NoFlags)
</span><span class="cx">     , m_backForwardList(WebBackForwardList::create(*this))
</span><span class="cx">     , m_loadStateAtProcessExit(FrameLoadState::State::Finished)
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     , m_temporarilyClosedComposition(false)
</span><ins>+#endif
</ins><span class="cx">     , m_textZoomFactor(1)
</span><span class="cx">     , m_pageZoomFactor(1)
</span><span class="cx">     , m_pageScaleFactor(1)
</span><span class="lines">@@ -3120,6 +3122,8 @@
</span><span class="cx"> {
</span><span class="cx"> #if PLATFORM(COCOA)
</span><span class="cx">     bool couldChangeSecureInputState = m_editorState.isInPasswordField != editorState.isInPasswordField || m_editorState.selectionIsNone;
</span><ins>+#endif
+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     bool closedComposition = !editorState.shouldIgnoreCompositionSelectionChange &amp;&amp; !editorState.hasComposition &amp;&amp; (m_editorState.hasComposition || m_temporarilyClosedComposition);
</span><span class="cx">     m_temporarilyClosedComposition = editorState.shouldIgnoreCompositionSelectionChange &amp;&amp; (m_temporarilyClosedComposition || m_editorState.hasComposition) &amp;&amp; !editorState.hasComposition;
</span><span class="cx"> #endif
</span><span class="lines">@@ -3130,10 +3134,12 @@
</span><span class="cx">     // Selection being none is a temporary state when editing. Flipping secure input state too quickly was causing trouble (not fully understood).
</span><span class="cx">     if (couldChangeSecureInputState &amp;&amp; !editorState.selectionIsNone)
</span><span class="cx">         m_pageClient.updateSecureInputState();
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">     if (editorState.shouldIgnoreCompositionSelectionChange)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     if (closedComposition)
</span><span class="cx">         m_pageClient.notifyInputContextAboutDiscardedComposition();
</span><span class="cx">     if (editorState.hasComposition) {
</span><span class="lines">@@ -3142,17 +3148,24 @@
</span><span class="cx">         cancelComposition();
</span><span class="cx">         m_pageClient.notifyInputContextAboutDiscardedComposition();
</span><span class="cx">     }
</span><del>-#if PLATFORM(IOS)
-    else {
</del><ins>+#elif PLATFORM(IOS)
+    if (!editorState.hasComposition) {
</ins><span class="cx">         // We need to notify the client on iOS to make sure the selection is redrawn.
</span><span class="cx">         notifyRevealedSelection();
</span><span class="cx">     }
</span><del>-#endif
</del><span class="cx"> #elif PLATFORM(EFL) || PLATFORM(GTK)
</span><span class="cx">     m_pageClient.updateTextInputState();
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPageProxy::compositionWasCanceled(const EditorState&amp; editorState)
+{
+#if PLATFORM(COCOA)
+    m_pageClient.notifyInputContextAboutDiscardedComposition();
+#endif
+    editorStateChanged(editorState);
+}
+
</ins><span class="cx"> // Undo management
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::registerEditCommandForUndo(uint64_t commandID, uint32_t editAction)
</span><span class="lines">@@ -4073,7 +4086,9 @@
</span><span class="cx"> 
</span><span class="cx">     // FIXME: Reset m_editorState.
</span><span class="cx">     // FIXME: Notify input methods about abandoned composition.
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     m_temporarilyClosedComposition = false;
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx">     dismissCorrectionPanel(ReasonForDismissingAlternativeTextIgnored);
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -1186,6 +1186,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     void editorStateChanged(const EditorState&amp;);
</span><ins>+    void compositionWasCanceled(const EditorState&amp;);
</ins><span class="cx"> 
</span><span class="cx">     // Back/Forward list management
</span><span class="cx">     void backForwardAddItem(uint64_t itemID);
</span><span class="lines">@@ -1470,7 +1471,9 @@
</span><span class="cx">     FrameLoadState::State m_loadStateAtProcessExit;
</span><span class="cx"> 
</span><span class="cx">     EditorState m_editorState;
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     bool m_temporarilyClosedComposition; // Editor state changed from hasComposition to !hasComposition, but that was only with shouldIgnoreCompositionSelectionChange yet.
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">     double m_textZoomFactor;
</span><span class="cx">     double m_pageZoomFactor;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxymessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Editor notifications
</span><span class="cx">     EditorStateChanged(WebKit::EditorState editorState)
</span><ins>+    CompositionWasCanceled(WebKit::EditorState editorState)
</ins><span class="cx"> 
</span><span class="cx">     # Find messages
</span><span class="cx">     DidCountStringMatches(String string, uint32_t matchCount)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessmacWebPageProxyMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -180,7 +180,9 @@
</span><span class="cx"> 
</span><span class="cx">     bool handled = true;
</span><span class="cx">     process().sendSync(Messages::WebPage::InsertText(text, replacementRange), Messages::WebPage::InsertText::Reply(handled, m_editorState), m_pageID);
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     m_temporarilyClosedComposition = false;
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx">     return handled;
</span><span class="cx"> }
</span><span class="lines">@@ -270,7 +272,9 @@
</span><span class="cx"> 
</span><span class="cx">     bool result = false;
</span><span class="cx">     process().sendSync(Messages::WebPage::ExecuteKeypressCommands(commands), Messages::WebPage::ExecuteKeypressCommands::Reply(result, m_editorState), m_pageID);
</span><ins>+#if PLATFORM(MAC) &amp;&amp; !USE(ASYNC_NSTEXTINPUTCLIENT)
</ins><span class="cx">     m_temporarilyClosedComposition = false;
</span><ins>+#endif
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (166420 => 166421)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-03-28 18:25:26 UTC (rev 166420)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-03-28 19:11:18 UTC (rev 166421)
</span><span class="lines">@@ -4109,7 +4109,18 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPage::didChangeSelection()
</span><span class="cx"> {
</span><del>-    send(Messages::WebPageProxy::EditorStateChanged(editorState()));
</del><ins>+#if (PLATFORM(MAC) &amp;&amp; USE(ASYNC_NSTEXTINPUTCLIENT)) || PLATFORM(IOS)
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+    // Abandon the current inline input session if selection changed for any other reason but an input method direct action.
+    // FIXME: Many changes that affect composition node do not go through didChangeSelection(). We need to do something when DOM manipulation affects the composition, because otherwise input method's idea about it will be different from Editor's.
+    // FIXME: We can't cancel composition when selection changes to NoSelection, but we probably should.
+    if (frame.editor().hasComposition() &amp;&amp; !frame.editor().ignoreCompositionSelectionChange() &amp;&amp; !frame.selection().isNone()) {
+        frame.editor().cancelComposition();
+        send(Messages::WebPageProxy::CompositionWasCanceled(editorState()));
+    } else
+#endif
+        send(Messages::WebPageProxy::EditorStateChanged(editorState()));
+
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     m_drawingArea-&gt;scheduleCompositingLayerFlush();
</span><span class="cx"> #endif
</span></span></pre>
</div>
</div>

</body>
</html>