<!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>[164401] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/164401">164401</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2014-02-19 16:12:59 -0800 (Wed, 19 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Changing selection shouldn't synchronously update editor UI components
https://bugs.webkit.org/show_bug.cgi?id=129024

Reviewed by Brent Fulgham.

Source/WebCore: 

Make updates to spellchecker, alternative text controller (correction pane), and delete button controller
asynchronous for programmatically triggered selection changes.

We continue to update their states synchronously immediately after we have applied, unapplied, or reapplied
editing commands to keep states in spell checker and alternative text controller consistent. We should be
able to make them asynchronous as well in the future but that should be done in a separate patch.

* WebCore.exp.in:
* editing/AlternativeTextController.cpp:
(WebCore::AlternativeTextController::respondToChangedSelection): This function used to enumerate all document
makers and call respondToMarkerAtEndOfWord on each one of them only to exit early when SetSelectionOptions
had DictationTriggered. This condition is now checked in Editor::respondToChangedSelection to avoid all the
unnecessary work and remove the dependency on SetSelectionOptions.
(WebCore::AlternativeTextController::respondToMarkerAtEndOfWord): Ditto.
* editing/AlternativeTextController.h:

* editing/Editor.cpp:
(WebCore::Editor::appliedEditing): Calls updateEditorUINowIfScheduled before calling respondToAppliedEditing
on the alternative text controller.
(WebCore::Editor::unappliedEditing): Ditto.
(WebCore::Editor::reappliedEditing): Ditto.
(WebCore::Editor::Editor): Initializes newly added booleans.
(WebCore::Editor::respondToChangedSelection): Continue to call respondToChangedSelection (for API consistency)
and setStartNewKillRingSequence but defer the &quot;editor UI updates&quot; to spellchecker, alternative text controller
and delete button controller by firing a newly added one shot timer.
(WebCore::Editor::updateEditorUINowIfScheduled): Synchronously update the pending editor UI updates.
(WebCore::Editor::editorUIUpdateTimerFired): Extracted from respondToChangedSelection.
* editing/Editor.h:

* testing/Internals.cpp:
(WebCore::Internals::markerCountForNode): Calls updateEditorUINowIfScheduled() to update document markers.
(WebCore::Internals::markerAt): Ditto.
(WebCore::Internals::updateEditorUINowIfScheduled): Added.
(WebCore::Internals::findEditingDeleteButton): Added. Updates delete button controller synchronously.
(WebCore::Internals::hasSpellingMarker): Calls updateEditorUINowIfScheduled() to update document markers.
(WebCore::Internals::hasAutocorrectedMarker): Ditto.
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit: 

Added symbols for internals.

* WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in:

LayoutTests: 

Many tests now calls internals.updateEditorUINowIfScheduled() to update the spellchecker states, and uses
setTimeout() to make things testable in the browser.

* editing/spelling/script-tests/spelling-backspace-between-lines.js:
(testTwoLinesMisspellings): Uses updateEditorUINowIfScheduled and setTimeout to make spellchecker recognize
two selection changes. This is okay since the user never moves selection multiple times in a single task.
* editing/spelling/spellcheck-attribute.html: Ditto.

* platform/mac/editing/deleting/deletionUI-click-on-delete-button.html: Use intenals.findEditingDeleteButton
which updates delete button controller states synchronously instead of getElementById which doesn't do that.
* platform/mac/editing/deleting/id-in-deletebutton-expected.txt:
* platform/mac/editing/deleting/id-in-deletebutton.html: Ditto. Also did some cleanups.
* platform/mac/editing/deleting/resources/deletionUI-helpers.js:
(deletionUIDeleteButtonForElement): Ditto.

* platform/mac/editing/spelling/editing-word-with-marker-1.html: Again, we must notify the spellchecker
synchronously here because we're expecting spellchecker to use the old selection set by setSelectionRange
in Editor::editorUIUpdateTimerFired triggered by the pasting command. This is, again, not a problem in
practice since user never pastes content synchronously after changing selection like this in a single task.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestseditingspellingscripttestsspellingbackspacebetweenlinesjs">trunk/LayoutTests/editing/spelling/script-tests/spelling-backspace-between-lines.js</a></li>
<li><a href="#trunkLayoutTestseditingspellingspellcheckattributehtml">trunk/LayoutTests/editing/spelling/spellcheck-attribute.html</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingdeletingdeletionUIclickondeletebuttonhtml">trunk/LayoutTests/platform/mac/editing/deleting/deletionUI-click-on-delete-button.html</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingdeletingidindeletebuttonexpectedtxt">trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton-expected.txt</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingdeletingidindeletebuttonhtml">trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton.html</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingdeletingresourcesdeletionUIhelpersjs">trunk/LayoutTests/platform/mac/editing/deleting/resources/deletionUI-helpers.js</a></li>
<li><a href="#trunkLayoutTestsplatformmaceditingspellingeditingwordwithmarker1html">trunk/LayoutTests/platform/mac/editing/spelling/editing-word-with-marker-1.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCoreexpin">trunk/Source/WebCore/WebCore.exp.in</a></li>
<li><a href="#trunkSourceWebCoreeditingAlternativeTextControllercpp">trunk/Source/WebCore/editing/AlternativeTextController.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingAlternativeTextControllerh">trunk/Source/WebCore/editing/AlternativeTextController.h</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorcpp">trunk/Source/WebCore/editing/Editor.cpp</a></li>
<li><a href="#trunkSourceWebCoreeditingEditorh">trunk/Source/WebCore/editing/Editor.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalscpp">trunk/Source/WebCore/testing/Internals.cpp</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsh">trunk/Source/WebCore/testing/Internals.h</a></li>
<li><a href="#trunkSourceWebCoretestingInternalsidl">trunk/Source/WebCore/testing/Internals.idl</a></li>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitWebKitvcxprojWebKitExportGeneratorWebKitExportsdefin">trunk/Source/WebKit/WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/ChangeLog        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2014-02-18  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Changing selection shouldn't synchronously update editor UI components
+        https://bugs.webkit.org/show_bug.cgi?id=129024
+
+        Reviewed by Brent Fulgham.
+
+        Many tests now calls internals.updateEditorUINowIfScheduled() to update the spellchecker states, and uses
+        setTimeout() to make things testable in the browser.
+
+        * editing/spelling/script-tests/spelling-backspace-between-lines.js:
+        (testTwoLinesMisspellings): Uses updateEditorUINowIfScheduled and setTimeout to make spellchecker recognize
+        two selection changes. This is okay since the user never moves selection multiple times in a single task.
+        * editing/spelling/spellcheck-attribute.html: Ditto.
+
+        * platform/mac/editing/deleting/deletionUI-click-on-delete-button.html: Use intenals.findEditingDeleteButton
+        which updates delete button controller states synchronously instead of getElementById which doesn't do that.
+        * platform/mac/editing/deleting/id-in-deletebutton-expected.txt:
+        * platform/mac/editing/deleting/id-in-deletebutton.html: Ditto. Also did some cleanups.
+        * platform/mac/editing/deleting/resources/deletionUI-helpers.js:
+        (deletionUIDeleteButtonForElement): Ditto.
+
+        * platform/mac/editing/spelling/editing-word-with-marker-1.html: Again, we must notify the spellchecker
+        synchronously here because we're expecting spellchecker to use the old selection set by setSelectionRange
+        in Editor::editorUIUpdateTimerFired triggered by the pasting command. This is, again, not a problem in
+        practice since user never pastes content synchronously after changing selection like this in a single task.
+
</ins><span class="cx"> 2014-02-19  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Another Windows update to quiet the bots.
</span></span></pre></div>
<a id="trunkLayoutTestseditingspellingscripttestsspellingbackspacebetweenlinesjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/spelling/script-tests/spelling-backspace-between-lines.js (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/spelling/script-tests/spelling-backspace-between-lines.js        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/editing/spelling/script-tests/spelling-backspace-between-lines.js        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -33,15 +33,19 @@
</span><span class="cx">     window.sel = setup(&quot;target1&quot;); // ^OK
</span><span class="cx"> 
</span><span class="cx">     sel.modify(&quot;move&quot;, &quot;forward&quot;, &quot;line&quot;); // ^OK zz OK
</span><del>-    for (var i = 0; i &lt; 3; i++)
-        sel.modify(&quot;move&quot;, &quot;forward&quot;, &quot;word&quot;);
</del><ins>+    if (window.internals)
+        internals.updateEditorUINowIfScheduled();
+    setTimeout(function () {
+        for (var i = 0; i &lt; 3; i++)
+            sel.modify(&quot;move&quot;, &quot;forward&quot;, &quot;word&quot;);
</ins><span class="cx"> 
</span><del>-    shouldBeEqualToString(&quot;firstLineText('target1')&quot;, &quot;OK&quot;);
-    shouldBeEqualToString(&quot;sel.anchorNode.data&quot;, &quot;OK zz OK&quot;);
-    if (window.internals)
-        shouldBecomeEqual(&quot;internals.hasSpellingMarker(3, 2)&quot;, &quot;true&quot;, done);
-    else
-        done();
</del><ins>+        shouldBeEqualToString(&quot;firstLineText('target1')&quot;, &quot;OK&quot;);
+        shouldBeEqualToString(&quot;sel.anchorNode.data&quot;, &quot;OK zz OK&quot;);
+        if (window.internals)
+            shouldBecomeEqual(&quot;internals.hasSpellingMarker(3, 2)&quot;, &quot;true&quot;, done);
+        else
+            done();
+    }, 100);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function testMisspellingsAfterLineMergeUsingDelete()
</span></span></pre></div>
<a id="trunkLayoutTestseditingspellingspellcheckattributehtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/editing/spelling/spellcheck-attribute.html (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/spelling/spellcheck-attribute.html        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/editing/spelling/spellcheck-attribute.html        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -48,14 +48,18 @@
</span><span class="cx">     var input = addInputElement(parentId, id, type, spellcheck);
</span><span class="cx">     input.focus();
</span><span class="cx">     // Activate spellchecking.
</span><del>-    moveSelectionForwardByWordCommand();
</del><ins>+    if (window.internals)
+        internals.updateEditorUINowIfScheduled();
+    setTimeout(function () {
+        moveSelectionForwardByWordCommand();
</ins><span class="cx"> 
</span><del>-    logMarkup(id, spellcheck, true);
</del><ins>+        logMarkup(id, spellcheck, true);
</ins><span class="cx"> 
</span><del>-    if (window.internals)
-        shouldBecomeEqual('internals.hasSpellingMarker(0, 2)', shouldBeMisspelled ? 'true' : 'false', done);
-    else
-        done();
</del><ins>+        if (window.internals)
+            shouldBecomeEqual('internals.hasSpellingMarker(0, 2)', shouldBeMisspelled ? 'true' : 'false', done);
+        else
+            done();
+    }, 10);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function logMarkup(id, spellcheckValue, shouldCloseTag)
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingdeletingdeletionUIclickondeletebuttonhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/editing/deleting/deletionUI-click-on-delete-button.html (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/deleting/deletionUI-click-on-delete-button.html        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/platform/mac/editing/deleting/deletionUI-click-on-delete-button.html        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -14,13 +14,13 @@
</span><span class="cx"> sel.setPosition(li, 0);
</span><span class="cx"> 
</span><span class="cx"> if (window.testRunner) {
</span><del>-    deleteButton = document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;);
</del><ins>+    deleteButton = internals.findEditingDeleteButton();
</ins><span class="cx">     x = deleteButton.offsetParent.offsetLeft + deleteButton.offsetParent.offsetParent.offsetLeft + deleteButton.offsetLeft + deleteButton.offsetWidth / 2;
</span><span class="cx">     y = deleteButton.offsetParent.offsetTop + deleteButton.offsetParent.offsetParent.offsetTop + deleteButton.offsetTop + deleteButton.offsetHeight / 2;
</span><span class="cx">     eventSender.mouseMoveTo(x, y);
</span><span class="cx">     eventSender.mouseDown();
</span><span class="cx">     eventSender.mouseUp();
</span><del>-    deleteButton = document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;);
</del><ins>+    deleteButton = internals.findEditingDeleteButton();
</ins><span class="cx">     testContainer = document.getElementById(&quot;test&quot;);
</span><span class="cx">     Markup.description(&quot;There should be no visible content in the markup below. This test is for a bug where the delete button wouldn't work because it had -webkit-user-select:none instead of -webkit-user-select:ignore.&quot;);
</span><span class="cx">     if (deleteButton)
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingdeletingidindeletebuttonexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton-expected.txt (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton-expected.txt        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton-expected.txt        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -3,7 +3,7 @@
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-PASS deleteButton is non-null.
</del><ins>+PASS internals.findEditingDeleteButton(); document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;) is non-null.
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingdeletingidindeletebuttonhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton.html (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton.html        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/platform/mac/editing/deleting/id-in-deletebutton.html        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1,12 +1,8 @@
</span><span class="cx"> &lt;html&gt;
</span><del>-&lt;head&gt;
-&lt;script src=&quot;../../../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
-&lt;/head&gt;
</del><span class="cx"> &lt;body&gt;
</span><del>-
</del><span class="cx"> &lt;div contenteditable=&quot;true&quot;&gt;
</span><span class="cx"> &lt;ul class=&quot;needsDeletionUI&quot;&gt;&lt;li&gt;1&lt;/li&gt;&lt;li id=&quot;li&quot;&gt;2&lt;/li&gt;&lt;/ul&gt;
</span><del>-
</del><ins>+&lt;script src=&quot;../../../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;script&gt;
</span><span class="cx"> description('Test document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;)');
</span><span class="cx"> 
</span><span class="lines">@@ -14,10 +10,11 @@
</span><span class="cx"> li = document.getElementById(&quot;li&quot;);
</span><span class="cx"> sel.setPosition(li, 0);
</span><span class="cx"> 
</span><del>-if (window.testRunner) {
-    deleteButton = document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;);
-    shouldBeNonNull('deleteButton');
-}
</del><ins>+if (window.testRunner)
+    shouldBeNonNull('internals.findEditingDeleteButton(); document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;)');
+
+var successfullyParsed = true;
+
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> &lt;script src=&quot;../../../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span><span class="cx"> &lt;/body&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingdeletingresourcesdeletionUIhelpersjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/editing/deleting/resources/deletionUI-helpers.js (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/deleting/resources/deletionUI-helpers.js        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/platform/mac/editing/deleting/resources/deletionUI-helpers.js        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -10,11 +10,12 @@
</span><span class="cx"> 
</span><span class="cx"> function deletionUIDeleteButtonForElement(id)
</span><span class="cx"> {
</span><ins>+    if (!window.internals)
+        return null;
</ins><span class="cx">     var sel = window.getSelection();
</span><span class="cx">     var selElement = document.getElementById(id);
</span><span class="cx">     sel.setPosition(selElement, 0);
</span><del>-    var deleteButton = document.getElementById(&quot;WebKit-Editing-Delete-Button&quot;);
-    return deleteButton;
</del><ins>+    return internals.findEditingDeleteButton();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function determineDeletionUIExistence(id)
</span></span></pre></div>
<a id="trunkLayoutTestsplatformmaceditingspellingeditingwordwithmarker1html"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/platform/mac/editing/spelling/editing-word-with-marker-1.html (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/platform/mac/editing/spelling/editing-word-with-marker-1.html        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/LayoutTests/platform/mac/editing/spelling/editing-word-with-marker-1.html        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -148,6 +148,8 @@
</span><span class="cx"> textarea.setSelectionRange(0,4);
</span><span class="cx"> execCopyCommand();
</span><span class="cx"> textarea.setSelectionRange(15, 15);
</span><ins>+if (window.internals)
+    internals.updateEditorUINowIfScheduled();
</ins><span class="cx"> execPasteCommand();
</span><span class="cx"> if (window.internals &amp;&amp; window.internals.hasSpellingMarker) {
</span><span class="cx">     if (window.internals.hasSpellingMarker(7,8) == 0) {
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/ChangeLog        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1,3 +1,49 @@
</span><ins>+2014-02-18  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Changing selection shouldn't synchronously update editor UI components
+        https://bugs.webkit.org/show_bug.cgi?id=129024
+
+        Reviewed by Brent Fulgham.
+
+        Make updates to spellchecker, alternative text controller (correction pane), and delete button controller
+        asynchronous for programmatically triggered selection changes.
+
+        We continue to update their states synchronously immediately after we have applied, unapplied, or reapplied
+        editing commands to keep states in spell checker and alternative text controller consistent. We should be
+        able to make them asynchronous as well in the future but that should be done in a separate patch.
+
+        * WebCore.exp.in:
+        * editing/AlternativeTextController.cpp:
+        (WebCore::AlternativeTextController::respondToChangedSelection): This function used to enumerate all document
+        makers and call respondToMarkerAtEndOfWord on each one of them only to exit early when SetSelectionOptions
+        had DictationTriggered. This condition is now checked in Editor::respondToChangedSelection to avoid all the
+        unnecessary work and remove the dependency on SetSelectionOptions.
+        (WebCore::AlternativeTextController::respondToMarkerAtEndOfWord): Ditto.
+        * editing/AlternativeTextController.h:
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::appliedEditing): Calls updateEditorUINowIfScheduled before calling respondToAppliedEditing
+        on the alternative text controller.
+        (WebCore::Editor::unappliedEditing): Ditto.
+        (WebCore::Editor::reappliedEditing): Ditto.
+        (WebCore::Editor::Editor): Initializes newly added booleans.
+        (WebCore::Editor::respondToChangedSelection): Continue to call respondToChangedSelection (for API consistency)
+        and setStartNewKillRingSequence but defer the &quot;editor UI updates&quot; to spellchecker, alternative text controller
+        and delete button controller by firing a newly added one shot timer.
+        (WebCore::Editor::updateEditorUINowIfScheduled): Synchronously update the pending editor UI updates.
+        (WebCore::Editor::editorUIUpdateTimerFired): Extracted from respondToChangedSelection.
+        * editing/Editor.h:
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::markerCountForNode): Calls updateEditorUINowIfScheduled() to update document markers.
+        (WebCore::Internals::markerAt): Ditto.
+        (WebCore::Internals::updateEditorUINowIfScheduled): Added.
+        (WebCore::Internals::findEditingDeleteButton): Added. Updates delete button controller synchronously.
+        (WebCore::Internals::hasSpellingMarker): Calls updateEditorUINowIfScheduled() to update document markers.
+        (WebCore::Internals::hasAutocorrectedMarker): Ditto.
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
</ins><span class="cx"> 2014-02-19  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add WTF_MAKE_FAST_ALLOCATED to more classes
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCoreexpin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.exp.in (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.exp.in        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/WebCore.exp.in        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1116,6 +1116,7 @@
</span><span class="cx"> __ZN7WebCore6Editor26toggleOverwriteModeEnabledEv
</span><span class="cx"> __ZN7WebCore6Editor26writeSelectionToPasteboardERNS_10PasteboardE
</span><span class="cx"> __ZN7WebCore6Editor28replaceSelectionWithFragmentEN3WTF10PassRefPtrINS_16DocumentFragmentEEEbbb
</span><ins>+__ZN7WebCore6Editor28updateEditorUINowIfScheduledEv
</ins><span class="cx"> __ZN7WebCore6Editor29canDecreaseSelectionListLevelEv
</span><span class="cx"> __ZN7WebCore6Editor29canIncreaseSelectionListLevelEv
</span><span class="cx"> __ZN7WebCore6Editor29handleAlternativeTextUIResultERKN3WTF6StringE
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingAlternativeTextControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/AlternativeTextController.cpp (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/AlternativeTextController.cpp        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/editing/AlternativeTextController.cpp        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -440,7 +440,7 @@
</span><span class="cx">     return view-&gt;contentsToRootView(IntRect(boundingRect));
</span><span class="cx"> }        
</span><span class="cx"> 
</span><del>-void AlternativeTextController::respondToChangedSelection(const VisibleSelection&amp; oldSelection, FrameSelection::SetSelectionOptions options)
</del><ins>+void AlternativeTextController::respondToChangedSelection(const VisibleSelection&amp; oldSelection)
</ins><span class="cx"> {
</span><span class="cx">     VisibleSelection currentSelection(m_frame.selection().selection());
</span><span class="cx">     // When user moves caret to the end of autocorrected word and pauses, we show the panel
</span><span class="lines">@@ -473,7 +473,7 @@
</span><span class="cx">         if (!marker)
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><del>-        if (respondToMarkerAtEndOfWord(*marker, position, options))
</del><ins>+        if (respondToMarkerAtEndOfWord(*marker, position))
</ins><span class="cx">             break;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -625,10 +625,8 @@
</span><span class="cx">     return (((marker.type() == DocumentMarker::Replacement &amp;&amp; !marker.description().isNull()) || marker.type() == DocumentMarker::Spelling || marker.type() == DocumentMarker::DictationAlternatives) &amp;&amp; static_cast&lt;int&gt;(marker.endOffset()) == endOffset);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AlternativeTextController::respondToMarkerAtEndOfWord(const DocumentMarker&amp; marker, const Position&amp; endOfWordPosition, FrameSelection::SetSelectionOptions options)
</del><ins>+bool AlternativeTextController::respondToMarkerAtEndOfWord(const DocumentMarker&amp; marker, const Position&amp; endOfWordPosition)
</ins><span class="cx"> {
</span><del>-    if (options &amp; FrameSelection::DictationTriggered)
-        return false;
</del><span class="cx">     if (!shouldStartTimerFor(marker, endOfWordPosition.offsetInContainerNode()))
</span><span class="cx">         return false;
</span><span class="cx">     Node* node = endOfWordPosition.containerNode();
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingAlternativeTextControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/AlternativeTextController.h (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/AlternativeTextController.h        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/editing/AlternativeTextController.h        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -108,7 +108,7 @@
</span><span class="cx">     void respondToUnappliedSpellCorrection(const VisibleSelection&amp;, const String&amp; corrected, const String&amp; correction) UNLESS_ENABLED({ UNUSED_PARAM(corrected); UNUSED_PARAM(correction); })
</span><span class="cx">     void respondToAppliedEditing(CompositeEditCommand*) UNLESS_ENABLED({ })
</span><span class="cx">     void respondToUnappliedEditing(EditCommandComposition*) UNLESS_ENABLED({ })
</span><del>-    void respondToChangedSelection(const VisibleSelection&amp; oldSelection, FrameSelection::SetSelectionOptions) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
</del><ins>+    void respondToChangedSelection(const VisibleSelection&amp; oldSelection) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
</ins><span class="cx"> 
</span><span class="cx">     void stopPendingCorrection(const VisibleSelection&amp; oldSelection) UNLESS_ENABLED({ UNUSED_PARAM(oldSelection); })
</span><span class="cx">     void applyPendingCorrection(const VisibleSelection&amp; selectionAfterTyping) UNLESS_ENABLED({ UNUSED_PARAM(selectionAfterTyping); })
</span><span class="lines">@@ -144,7 +144,7 @@
</span><span class="cx">     String markerDescriptionForAppliedAlternativeText(AlternativeTextType, DocumentMarker::MarkerType);
</span><span class="cx"> 
</span><span class="cx">     bool shouldStartTimerFor(const DocumentMarker&amp;, int endOffset) const;
</span><del>-    bool respondToMarkerAtEndOfWord(const DocumentMarker&amp;, const Position&amp; endOfWordPosition, FrameSelection::SetSelectionOptions);
</del><ins>+    bool respondToMarkerAtEndOfWord(const DocumentMarker&amp;, const Position&amp; endOfWordPosition);
</ins><span class="cx"> 
</span><span class="cx">     AlternativeTextClient* alternativeTextClient();
</span><span class="cx">     EditorClient* editorClient();
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.cpp (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.cpp        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/editing/Editor.cpp        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1066,8 +1066,6 @@
</span><span class="cx">     ASSERT(composition);
</span><span class="cx">     VisibleSelection newSelection(cmd-&gt;endingSelection());
</span><span class="cx"> 
</span><del>-    m_alternativeTextController-&gt;respondToAppliedEditing(cmd.get());
-
</del><span class="cx">     notifyTextFromControls(composition-&gt;startingRootEditableElement(), composition-&gt;endingRootEditableElement());
</span><span class="cx"> 
</span><span class="cx">     // Don't clear the typing style with this selection change.  We do those things elsewhere if necessary.
</span><span class="lines">@@ -1075,6 +1073,10 @@
</span><span class="cx">     changeSelectionAfterCommand(newSelection, options);
</span><span class="cx">     dispatchEditableContentChangedEvents(composition-&gt;startingRootEditableElement(), composition-&gt;endingRootEditableElement());
</span><span class="cx"> 
</span><ins>+    updateEditorUINowIfScheduled();
+    
+    m_alternativeTextController-&gt;respondToAppliedEditing(cmd.get());
+
</ins><span class="cx">     if (!cmd-&gt;preservesTypingStyle())
</span><span class="cx">         m_frame.selection().clearTypingStyle();
</span><span class="cx"> 
</span><span class="lines">@@ -1102,6 +1104,8 @@
</span><span class="cx">     changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions());
</span><span class="cx">     dispatchEditableContentChangedEvents(cmd-&gt;startingRootEditableElement(), cmd-&gt;endingRootEditableElement());
</span><span class="cx"> 
</span><ins>+    updateEditorUINowIfScheduled();
+
</ins><span class="cx">     m_alternativeTextController-&gt;respondToUnappliedEditing(cmd.get());
</span><span class="cx"> 
</span><span class="cx">     m_lastEditCommand = 0;
</span><span class="lines">@@ -1119,6 +1123,8 @@
</span><span class="cx">     VisibleSelection newSelection(cmd-&gt;endingSelection());
</span><span class="cx">     changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions());
</span><span class="cx">     dispatchEditableContentChangedEvents(cmd-&gt;startingRootEditableElement(), cmd-&gt;endingRootEditableElement());
</span><ins>+    
+    updateEditorUINowIfScheduled();
</ins><span class="cx"> 
</span><span class="cx">     m_lastEditCommand = 0;
</span><span class="cx">     if (client())
</span><span class="lines">@@ -1141,6 +1147,9 @@
</span><span class="cx">     , m_areMarkedTextMatchesHighlighted(false)
</span><span class="cx">     , m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv)
</span><span class="cx">     , m_overwriteModeEnabled(false)
</span><ins>+    , m_editorUIUpdateTimer(this, &amp;Editor::editorUIUpdateTimerFired)
+    , m_editorUIUpdateTimerShouldCheckSpellingAndGrammar(false)
+    , m_editorUIUpdateTimerWasTriggeredByDictation(false)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -3294,7 +3303,7 @@
</span><span class="cx">     document().markers().repaintMarkers(DocumentMarker::TextMatch);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Editor::respondToChangedSelection(const VisibleSelection&amp; oldSelection, FrameSelection::SetSelectionOptions options)
</del><ins>+void Editor::respondToChangedSelection(const VisibleSelection&amp;, FrameSelection::SetSelectionOptions options)
</ins><span class="cx"> {
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     // FIXME: Should suppress selection change notifications during a composition change &lt;https://webkit.org/b/38830&gt; 
</span><span class="lines">@@ -3302,9 +3311,34 @@
</span><span class="cx">         return;
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    if (client())
+        client()-&gt;respondToChangedSelection(&amp;m_frame);
+    setStartNewKillRingSequence(true);
+
+    if (m_editorUIUpdateTimer.isActive())
+        return;
+
+    // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
+    m_editorUIUpdateTimerShouldCheckSpellingAndGrammar = options &amp; FrameSelection::CloseTyping
+        &amp;&amp; !(options &amp; FrameSelection::SpellCorrectionTriggered);
+    m_editorUIUpdateTimerWasTriggeredByDictation = options &amp; FrameSelection::DictationTriggered;
+    m_editorUIUpdateTimer.startOneShot(0);
+}
+
+void Editor::updateEditorUINowIfScheduled()
+{
+    if (!m_editorUIUpdateTimer.isActive())
+        return;
+    m_editorUIUpdateTimer.stop();
+    editorUIUpdateTimerFired(m_editorUIUpdateTimer);
+}
+
+void Editor::editorUIUpdateTimerFired(Timer&lt;Editor&gt;&amp;)
+{
+    VisibleSelection oldSelection = m_oldSelectionForEditorUIUpdate;
+
</ins><span class="cx">     m_alternativeTextController-&gt;stopPendingCorrection(oldSelection);
</span><del>-
-    bool closeTyping = options &amp; FrameSelection::CloseTyping;
</del><ins>+    
</ins><span class="cx">     bool isContinuousSpellCheckingEnabled = this-&gt;isContinuousSpellCheckingEnabled();
</span><span class="cx">     bool isContinuousGrammarCheckingEnabled = isContinuousSpellCheckingEnabled &amp;&amp; isGrammarCheckingEnabled();
</span><span class="cx">     if (isContinuousSpellCheckingEnabled) {
</span><span class="lines">@@ -3331,13 +3365,10 @@
</span><span class="cx">                 newSelectedSentence = VisibleSelection(startOfSentence(newStart), endOfSentence(newStart));
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        // Don't check spelling and grammar if the change of selection is triggered by spelling correction itself.
-        bool shouldCheckSpellingAndGrammar = !(options &amp; FrameSelection::SpellCorrectionTriggered);
-
</del><span class="cx">         // When typing we check spelling elsewhere, so don't redo it here.
</span><span class="cx">         // If this is a change in selection resulting from a delete operation,
</span><span class="cx">         // oldSelection may no longer be in the document.
</span><del>-        if (shouldCheckSpellingAndGrammar &amp;&amp; closeTyping &amp;&amp; oldSelection.isContentEditable() &amp;&amp; oldSelection.start().deprecatedNode() &amp;&amp; oldSelection.start().anchorNode()-&gt;inDocument()) {
</del><ins>+        if (m_editorUIUpdateTimerShouldCheckSpellingAndGrammar &amp;&amp; oldSelection.isContentEditable() &amp;&amp; oldSelection.start().deprecatedNode() &amp;&amp; oldSelection.start().anchorNode()-&gt;inDocument()) {
</ins><span class="cx">             VisiblePosition oldStart(oldSelection.visibleStart());
</span><span class="cx">             VisibleSelection oldAdjacentWords = VisibleSelection(startOfWord(oldStart, LeftWordIfOnBoundary), endOfWord(oldStart, RightWordIfOnBoundary));
</span><span class="cx">             if (oldAdjacentWords != newAdjacentWords) {
</span><span class="lines">@@ -3365,13 +3396,13 @@
</span><span class="cx">     if (!isContinuousGrammarCheckingEnabled)
</span><span class="cx">         document().markers().removeMarkers(DocumentMarker::Grammar);
</span><span class="cx"> 
</span><del>-    if (client())
-        client()-&gt;respondToChangedSelection(&amp;m_frame);
-    setStartNewKillRingSequence(true);
</del><span class="cx"> #if ENABLE(DELETION_UI)
</span><span class="cx">     m_deleteButtonController-&gt;respondToChangedSelection(oldSelection);
</span><span class="cx"> #endif
</span><del>-    m_alternativeTextController-&gt;respondToChangedSelection(oldSelection, options);
</del><ins>+    if (m_editorUIUpdateTimerWasTriggeredByDictation)
+        m_alternativeTextController-&gt;respondToChangedSelection(oldSelection);
+
+    m_oldSelectionForEditorUIUpdate = m_frame.selection().selection();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static Node* findFirstMarkable(Node* node)
</span></span></pre></div>
<a id="trunkSourceWebCoreeditingEditorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/editing/Editor.h (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/Editor.h        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/editing/Editor.h        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -362,6 +362,7 @@
</span><span class="cx">     IntRect firstRectForRange(Range*) const;
</span><span class="cx"> 
</span><span class="cx">     void respondToChangedSelection(const VisibleSelection&amp; oldSelection, FrameSelection::SetSelectionOptions);
</span><ins>+    void updateEditorUINowIfScheduled();
</ins><span class="cx">     bool shouldChangeSelection(const VisibleSelection&amp; oldSelection, const VisibleSelection&amp; newSelection, EAffinity, bool stillSelecting) const;
</span><span class="cx">     unsigned countMatchesForText(const String&amp;, Range*, FindOptions, unsigned limit, bool markMatches, Vector&lt;RefPtr&lt;Range&gt;&gt;*);
</span><span class="cx">     bool markedTextMatchesAreHighlighted() const;
</span><span class="lines">@@ -464,6 +465,8 @@
</span><span class="cx"> 
</span><span class="cx">     void changeSelectionAfterCommand(const VisibleSelection&amp; newSelection, FrameSelection::SetSelectionOptions);
</span><span class="cx"> 
</span><ins>+    void editorUIUpdateTimerFired(Timer&lt;Editor&gt;&amp;);
+
</ins><span class="cx">     Node* findEventTargetFromSelection() const;
</span><span class="cx"> 
</span><span class="cx">     bool unifiedTextCheckerEnabled() const;
</span><span class="lines">@@ -495,6 +498,11 @@
</span><span class="cx">     bool m_areMarkedTextMatchesHighlighted;
</span><span class="cx">     EditorParagraphSeparator m_defaultParagraphSeparator;
</span><span class="cx">     bool m_overwriteModeEnabled;
</span><ins>+
+    VisibleSelection m_oldSelectionForEditorUIUpdate;
+    Timer&lt;Editor&gt; m_editorUIUpdateTimer;
+    bool m_editorUIUpdateTimerShouldCheckSpellingAndGrammar;
+    bool m_editorUIUpdateTimerWasTriggeredByDictation;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> inline void Editor::setStartNewKillRingSequence(bool flag)
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.cpp (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.cpp        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/testing/Internals.cpp        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -748,6 +748,8 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    node-&gt;document().frame()-&gt;editor().updateEditorUINowIfScheduled();
+
</ins><span class="cx">     return node-&gt;document().markers().markersFor(node, markerTypes).size();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -765,6 +767,8 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    node-&gt;document().frame()-&gt;editor().updateEditorUINowIfScheduled();
+
</ins><span class="cx">     Vector&lt;DocumentMarker*&gt; markers = node-&gt;document().markers().markersFor(node, markerTypes);
</span><span class="cx">     if (markers.size() &lt;= index)
</span><span class="cx">         return 0;
</span><span class="lines">@@ -1295,12 +1299,34 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Internals::updateEditorUINowIfScheduled()
+{
+    if (Document* document = contextDocument()) {
+        if (Frame* frame = document-&gt;frame())
+            frame-&gt;editor().updateEditorUINowIfScheduled();
+    }
+}
+
+Node* Internals::findEditingDeleteButton()
+{
+    Document* document = contextDocument();
+    if (!document || !document-&gt;frame())
+        return 0;
+
+    updateEditorUINowIfScheduled();
+
+    // FIXME: We shouldn't pollute the id namespace with this name.
+    return document-&gt;getElementById(&quot;WebKit-Editing-Delete-Button&quot;);
+}
+
</ins><span class="cx"> bool Internals::hasSpellingMarker(int from, int length, ExceptionCode&amp;)
</span><span class="cx"> {
</span><span class="cx">     Document* document = contextDocument();
</span><span class="cx">     if (!document || !document-&gt;frame())
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><ins>+    updateEditorUINowIfScheduled();
+
</ins><span class="cx">     return document-&gt;frame()-&gt;editor().selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
</span><span class="cx"> }
</span><span class="cx">     
</span><span class="lines">@@ -1309,7 +1335,9 @@
</span><span class="cx">     Document* document = contextDocument();
</span><span class="cx">     if (!document || !document-&gt;frame())
</span><span class="cx">         return 0;
</span><del>-    
</del><ins>+
+    updateEditorUINowIfScheduled();
+
</ins><span class="cx">     return document-&gt;frame()-&gt;editor().selectionStartHasMarkerFor(DocumentMarker::Autocorrected, from, length);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.h (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.h        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/testing/Internals.h        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -169,6 +169,9 @@
</span><span class="cx"> 
</span><span class="cx">     String parserMetaData(Deprecated::ScriptValue = Deprecated::ScriptValue());
</span><span class="cx"> 
</span><ins>+    Node* findEditingDeleteButton();
+    void updateEditorUINowIfScheduled();
+
</ins><span class="cx">     bool hasSpellingMarker(int from, int length, ExceptionCode&amp;);
</span><span class="cx">     bool hasGrammarMarker(int from, int length, ExceptionCode&amp;);
</span><span class="cx">     bool hasAutocorrectedMarker(int from, int length, ExceptionCode&amp;);
</span></span></pre></div>
<a id="trunkSourceWebCoretestingInternalsidl"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/testing/Internals.idl (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/testing/Internals.idl        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebCore/testing/Internals.idl        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -129,6 +129,10 @@
</span><span class="cx">     // Calling parserMetaData() with no arguments gets the metadata for the script of the current scope.
</span><span class="cx">     DOMString parserMetaData(optional any func);
</span><span class="cx"> 
</span><ins>+    void updateEditorUINowIfScheduled();
+
+    Node findEditingDeleteButton();
+
</ins><span class="cx">     [RaisesException] boolean hasSpellingMarker(long from, long length);
</span><span class="cx">     [RaisesException] boolean hasGrammarMarker(long from, long length);
</span><span class="cx">     [RaisesException] boolean hasAutocorrectedMarker(long from, long length);
</span></span></pre></div>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebKit/ChangeLog        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2014-02-18  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Changing selection shouldn't synchronously update editor UI components
+        https://bugs.webkit.org/show_bug.cgi?id=129024
+
+        Reviewed by Brent Fulgham.
+
+        Added symbols for internals.
+
+        * WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in:
+
</ins><span class="cx"> 2014-02-17  Sergio Correia  &lt;sergio.correia@openbossa.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Replace uses of PassOwnPtr/OwnPtr with std::unique_ptr in WebCore/inspector
</span></span></pre></div>
<a id="trunkSourceWebKitWebKitvcxprojWebKitExportGeneratorWebKitExportsdefin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in (164400 => 164401)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in        2014-02-19 23:51:34 UTC (rev 164400)
+++ trunk/Source/WebKit/WebKit.vcxproj/WebKitExportGenerator/WebKitExports.def.in        2014-02-20 00:12:59 UTC (rev 164401)
</span><span class="lines">@@ -204,6 +204,7 @@
</span><span class="cx">         symbolWithPointer(?garbageCollectDocumentResources@CachedResourceLoader@WebCore@@QAEXXZ, ?garbageCollectDocumentResources@CachedResourceLoader@WebCore@@QEAAXXZ)
</span><span class="cx">         symbolWithPointer(?getCachedDOMStructure@WebCore@@YAPAVStructure@JSC@@PAVJSDOMGlobalObject@1@PBUClassInfo@3@@Z, ?getCachedDOMStructure@WebCore@@YAPEAVStructure@JSC@@PEAVJSDOMGlobalObject@1@PEBUClassInfo@3@@Z)
</span><span class="cx">         symbolWithPointer(?getData16SlowCase@StringImpl@WTF@@ABEPB_WXZ, ?getData16SlowCase@StringImpl@WTF@@AEBAPEB_WXZ)
</span><ins>+        symbolWithPointer(?getElementById@TreeScope@WebCore@@QBEPAVElement@2@ABVAtomicString@WTF@@@Z)
</ins><span class="cx">         symbolWithPointer(?getLocationAndLengthFromRange@TextIterator@WebCore@@SA_NPAVNode@2@PBVRange@2@AAI2@Z, ?getLocationAndLengthFromRange@TextIterator@WebCore@@SA_NPEAVNode@2@PEBVRange@2@AEA_K2@Z)
</span><span class="cx">         symbolWithPointer(?hitTest@RenderView@WebCore@@QAE_NABVHitTestRequest@2@AAVHitTestResult@2@@Z, ?hitTest@RenderView@WebCore@@QEAA_NAEBVHitTestRequest@2@AEAVHitTestResult@2@@Z)
</span><span class="cx">         ?inputTag@HTMLNames@WebCore@@3VQualifiedName@2@B
</span><span class="lines">@@ -323,6 +324,7 @@
</span><span class="cx">         symbolWithPointer(?toJS@WebCore@@YA?AVJSValue@JSC@@PAVExecState@3@PAVJSDOMGlobalObject@1@PAVNodeList@1@@Z, ?toJS@WebCore@@YA?AVJSValue@JSC@@PEAVExecState@3@PEAVJSDOMGlobalObject@1@PEAVNodeList@1@@Z)
</span><span class="cx">         symbolWithPointer(?toRange@WebCore@@YAPAVRange@1@VJSValue@JSC@@@Z, ?toRange@WebCore@@YAPEAVRange@1@VJSValue@JSC@@@Z)
</span><span class="cx">         symbolWithPointer(?isTreeScope@Node@WebCore@@QBE_NXZ, ?isTreeScope@Node@WebCore@@QEBA_NXZ)
</span><ins>+        symbolWithPointer(?updateEditorUINowIfScheduled@Editor@WebCore@@QAEXXZ)
</ins><span class="cx">         symbolWithPointer(?updateLayoutIgnorePendingStylesheets@Document@WebCore@@QAEXXZ, ?updateLayoutIgnorePendingStylesheets@Document@WebCore@@QEAAXXZ)
</span><span class="cx">         symbolWithPointer(?updateStyleIfNeeded@Document@WebCore@@QAEXXZ, ?updateStyleIfNeeded@Document@WebCore@@QEAAXXZ)
</span><span class="cx">         symbolWithPointer(?view@Document@WebCore@@QBEPAVFrameView@2@XZ, ?view@Document@WebCore@@QEBAPEAVFrameView@2@XZ)
</span></span></pre>
</div>
</div>

</body>
</html>