<!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>[179578] 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/179578">179578</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-02-03 16:18:40 -0800 (Tue, 03 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS] Selection Callout should not immediately disappear on pages with frequent layouts
https://bugs.webkit.org/show_bug.cgi?id=141210

Patch by Joseph Pecoraro &lt;pecoraro@apple.com&gt; on 2015-02-03
Reviewed by Enrica Casucci.

In iOS WebKit2 in order to keep caret refreshes in sync with WebCore layouts
the selection assistant is told to update whenever WebKit's layer tree
commits. Unfortunately, for pages with JavaScript animation that are
frequently doing a layout / layer tree update, this would trigger very
frequent selection updates that would keep the caret from blinking and
dismiss any selection callouts.

This change tracks the last selection drawing information so that we can
avoid informing the assistant of a selection updates unless it has changed
visually or needs to redraw (zoom).

* Shared/EditorState.cpp:
Remove include already in header.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(WebKit::WKSelectionDrawingInfo::WKSelectionDrawingInfo):
(WebKit::operator==):
(WebKit::operator!=):
(-[WKContentView observeValueForKeyPath:ofObject:change:context:]):
When zooming, force the selection update, even though the drawing
information hasn't changed, the views will need to be updated.

(-[WKContentView _updateChangedSelection]):
(-[WKContentView _updateChangedSelection:]):
Monitor EditorState for changes in selection drawing and avoid
informing the selection assistant unless necessary.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2SharedEditorStatecpp">trunk/Source/WebKit2/Shared/EditorState.cpp</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionh">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (179577 => 179578)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-02-04 00:07:49 UTC (rev 179577)
+++ trunk/Source/WebKit2/ChangeLog        2015-02-04 00:18:40 UTC (rev 179578)
</span><span class="lines">@@ -1,3 +1,38 @@
</span><ins>+2015-02-03  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
+
+        [iOS] Selection Callout should not immediately disappear on pages with frequent layouts
+        https://bugs.webkit.org/show_bug.cgi?id=141210
+
+        Reviewed by Enrica Casucci.
+
+        In iOS WebKit2 in order to keep caret refreshes in sync with WebCore layouts
+        the selection assistant is told to update whenever WebKit's layer tree
+        commits. Unfortunately, for pages with JavaScript animation that are
+        frequently doing a layout / layer tree update, this would trigger very
+        frequent selection updates that would keep the caret from blinking and
+        dismiss any selection callouts.
+
+        This change tracks the last selection drawing information so that we can
+        avoid informing the assistant of a selection updates unless it has changed
+        visually or needs to redraw (zoom).
+
+        * Shared/EditorState.cpp:
+        Remove include already in header.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (WebKit::WKSelectionDrawingInfo::WKSelectionDrawingInfo):
+        (WebKit::operator==):
+        (WebKit::operator!=):
+        (-[WKContentView observeValueForKeyPath:ofObject:change:context:]):
+        When zooming, force the selection update, even though the drawing
+        information hasn't changed, the views will need to be updated.
+
+        (-[WKContentView _updateChangedSelection]):
+        (-[WKContentView _updateChangedSelection:]):
+        Monitor EditorState for changes in selection drawing and avoid
+        informing the selection assistant unless necessary.
+
</ins><span class="cx"> 2015-02-03  Jeremy Jones  &lt;jeremyj@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Prevent flicker when exiting fullscreen by synchronizing transactions.
</span></span></pre></div>
<a id="trunkSourceWebKit2SharedEditorStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/EditorState.cpp (179577 => 179578)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/EditorState.cpp        2015-02-04 00:07:49 UTC (rev 179577)
+++ trunk/Source/WebKit2/Shared/EditorState.cpp        2015-02-04 00:18:40 UTC (rev 179578)
</span><span class="lines">@@ -29,10 +29,6 @@
</span><span class="cx"> #include &quot;Arguments.h&quot;
</span><span class="cx"> #include &quot;WebCoreArgumentCoders.h&quot;
</span><span class="cx"> 
</span><del>-#if PLATFORM(IOS)
-#include &lt;WebCore/SelectionRect.h&gt;
-#endif
-
</del><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="cx"> void EditorState::encode(IPC::ArgumentEncoder&amp; encoder) const
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h (179577 => 179578)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h        2015-02-04 00:07:49 UTC (rev 179577)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h        2015-02-04 00:18:40 UTC (rev 179578)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #import &quot;WKContentView.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #import &quot;AssistedNodeInformation.h&quot;
</span><ins>+#import &quot;EditorState.h&quot;
</ins><span class="cx"> #import &quot;GestureTypes.h&quot;
</span><span class="cx"> #import &quot;InteractionInformationAtPosition.h&quot;
</span><span class="cx"> #import &quot;UIKitSPI.h&quot;
</span><span class="lines">@@ -71,6 +72,14 @@
</span><span class="cx"> typedef void (^UIWKSelectionWithDirectionCompletionHandler)(BOOL selectionEndIsMoving);
</span><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><ins>+struct WKSelectionDrawingInfo {
+    enum class SelectionType { None, Plugin, Range };
+    WKSelectionDrawingInfo();
+    explicit WKSelectionDrawingInfo(const EditorState&amp;);
+    SelectionType type;
+    WebCore::IntRect caretRect;
+    Vector&lt;WebCore::SelectionRect&gt; selectionRects;
+};
</ins><span class="cx"> struct WKAutoCorrectionData {
</span><span class="cx">     String fontName;
</span><span class="cx">     CGFloat fontSize;
</span><span class="lines">@@ -129,6 +138,8 @@
</span><span class="cx"> 
</span><span class="cx">     CGPoint _lastInteractionLocation;
</span><span class="cx"> 
</span><ins>+    WebKit::WKSelectionDrawingInfo _lastSelectionDrawingInfo;
+
</ins><span class="cx">     BOOL _isEditable;
</span><span class="cx">     BOOL _showingTextStyleOptions;
</span><span class="cx">     BOOL _hasValidPositionInformation;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (179577 => 179578)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2015-02-04 00:07:49 UTC (rev 179577)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2015-02-04 00:18:40 UTC (rev 179578)
</span><span class="lines">@@ -65,6 +65,58 @@
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> using namespace WebKit;
</span><span class="cx"> 
</span><ins>+namespace WebKit {
+
+WKSelectionDrawingInfo::WKSelectionDrawingInfo()
+    : type(SelectionType::None)
+{
+}
+
+WKSelectionDrawingInfo::WKSelectionDrawingInfo(const EditorState&amp; editorState)
+{
+    if (editorState.selectionIsNone) {
+        type = SelectionType::None;
+        return;
+    }
+
+    if (editorState.isInPlugin) {
+        type = SelectionType::Plugin;
+        return;
+    }
+
+    type = SelectionType::Range;
+    caretRect = editorState.caretRectAtEnd;
+    selectionRects = editorState.selectionRects;
+}
+
+inline bool operator==(const WKSelectionDrawingInfo&amp; a, const WKSelectionDrawingInfo&amp; b)
+{
+    if (a.type != b.type)
+        return false;
+
+    if (a.type == WKSelectionDrawingInfo::SelectionType::Range) {
+        if (a.caretRect != b.caretRect)
+            return false;
+
+        if (a.selectionRects.size() != b.selectionRects.size())
+            return false;
+
+        for (unsigned i = 0; i &lt; a.selectionRects.size(); ++i) {
+            if (a.selectionRects[i].rect() != b.selectionRects[i].rect())
+                return false;
+        }
+    }
+
+    return true;
+}
+
+inline bool operator!=(const WKSelectionDrawingInfo&amp; a, const WKSelectionDrawingInfo&amp; b)
+{
+    return !(a == b);
+}
+
+} // namespace WebKit
+
</ins><span class="cx"> static const float highlightDelay = 0.12;
</span><span class="cx"> static const float tapAndHoldDelay  = 0.75;
</span><span class="cx"> const CGFloat minimumTapHighlightRadius = 2.0;
</span><span class="lines">@@ -382,7 +434,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _selectionNeedsUpdate = YES;
</span><del>-    [self _updateChangedSelection];
</del><ins>+    [self _updateChangedSelection:YES];
</ins><span class="cx">     [self _updateTapHighlight];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2755,9 +2807,20 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)_updateChangedSelection
</span><span class="cx"> {
</span><ins>+    [self _updateChangedSelection:NO];
+}
+
+- (void)_updateChangedSelection:(BOOL)force
+{
</ins><span class="cx">     if (!_selectionNeedsUpdate)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    WKSelectionDrawingInfo selectionDrawingInfo(_page-&gt;editorState());
+    if (!force &amp;&amp; selectionDrawingInfo == _lastSelectionDrawingInfo)
+        return;
+
+    _lastSelectionDrawingInfo = selectionDrawingInfo;
+
</ins><span class="cx">     // FIXME: We need to figure out what to do if the selection is changed by Javascript.
</span><span class="cx">     if (_textSelectionAssistant) {
</span><span class="cx">         _markedText = (_page-&gt;editorState().hasComposition) ? _page-&gt;editorState().markedText : String();
</span></span></pre>
</div>
</div>

</body>
</html>