<!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>[164497] trunk/Source</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/164497">164497</a></dd>
<dt>Author</dt> <dd>enrica@apple.com</dd>
<dt>Date</dt> <dd>2014-02-21 13:56:14 -0800 (Fri, 21 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Support WebSelections in WK2 on iOS.
https://bugs.webkit.org/show_bug.cgi?id=127015
&lt;rdar://problem/15211964&gt;

Reviewed by Benjamin Poulain.

../WebCore: 

Adding some exports.

* WebCore.exp.in:

../WebKit2: 

This is the remaining work on block selections for iOS in WK2.
Once a block selection has been created with a long press gesture
on a selectable area, we can interact with it by touching the four
handles at the top, right, bottom and left side of the selection box.
Expanding or shrinking a block selection requires finding the next/previous
block in the direction of the movement, depending on the handle we
are interacting with.
Every time a new block is selected, we compute the thresholds required
to trigger another block change. The thresholds are sent back to the
UIProcess that will use this information to decide when to activate
the new selection, either bigger or smaller.
This patch also fixes a bug in selectWithTwoTouches where the points
were not mapped to the active frame.

* Shared/ios/WKGestureTypes.h:
* UIProcess/API/ios/PageClientImplIOS.h:
* UIProcess/API/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::didUpdateBlockSelectionWithTouches):
* UIProcess/API/ios/WKContentView.mm:
(-[WKContentView _didUpdateBlockSelectionWithTouches:withFlags:growThreshold:shrinkThreshold:]):
* UIProcess/API/ios/WKContentViewInternal.h:
* UIProcess/API/ios/WKInteractionView.h:
* UIProcess/API/ios/WKInteractionView.mm:
(-[WKInteractionView hasSelectablePositionAtPoint:]):
(-[WKInteractionView clearSelection]):
(toWKHandlePosition):
(-[WKInteractionView _didUpdateBlockSelectionWithTouches:WebKit::withFlags:WebKit::growThreshold:shrinkThreshold:]):
(-[WKInteractionView changeBlockSelectionWithTouchAt:withSelectionTouch:forHandle:]):
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::updateBlockSelectionWithTouches):
(WebKit::WebPageProxy::didUpdateBlockSelectionWithTouches):
* WebProcess/WebPage/WebPage.cpp:
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::rangeForWebSelectionAtPosition):
(WebKit::WebPage::rangeForBlockAtPoint):
(WebKit::WebPage::selectWithGesture):
(WebKit::distanceBetweenRectsForPosition):
(WebKit::rectsEssentiallyTheSame):
(WebKit::containsRange):
(WebKit::unionDOMRanges):
(WebKit::computeEdgeCenter):
(WebKit::WebPage::expandedRangeFromHandle):
(WebKit::WebPage::contractedRangeFromHandle):
(WebKit::WebPage::computeExpandAndShrinkThresholdsForHandle):
(WebKit::shouldExpand):
(WebKit::WebPage::changeBlockSelection):
(WebKit::WebPage::updateBlockSelectionWithTouches):
(WebKit::WebPage::clearSelection):
(WebKit::WebPage::selectWithTwoTouches):
(WebKit::WebPage::getPositionInformation):</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2SharediosWKGestureTypesh">trunk/Source/WebKit2/Shared/ios/WKGestureTypes.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosPageClientImplIOSh">trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosPageClientImplIOSmm">trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosWKContentViewmm">trunk/Source/WebKit2/UIProcess/API/ios/WKContentView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosWKContentViewInternalh">trunk/Source/WebKit2/UIProcess/API/ios/WKContentViewInternal.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosWKInteractionViewh">trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPIiosWKInteractionViewmm">trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessPageClienth">trunk/Source/WebKit2/UIProcess/PageClient.h</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="#trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm">trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageWebPagecpp">trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp</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>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebCore/ChangeLog        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2014-02-21  Enrica Casucci  &lt;enrica@apple.com&gt;
+
+        Support WebSelections in WK2 on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=127015
+        &lt;rdar://problem/15211964&gt;
+
+        Reviewed by Benjamin Poulain.
+
+        Adding some exports.
+
+        * WebCore.exp.in:
+
</ins><span class="cx"> 2014-02-21  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         'mouseenter' mouse compat event not fired when listeners for touch events
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCoreexpin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.exp.in (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.exp.in        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebCore/WebCore.exp.in        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -1745,7 +1745,10 @@
</span><span class="cx"> __ZNK7WebCore5Frame16frameScaleFactorEv
</span><span class="cx"> __ZNK7WebCore5Frame25trackedRepaintRectsAsTextEv
</span><span class="cx"> __ZNK7WebCore5Frame31displayStringModifiedByEncodingERKN3WTF6StringE
</span><ins>+__ZNK7WebCore5Range10cloneRangeERi
+__ZNK7WebCore5Range11boundingBoxEv
</ins><span class="cx"> __ZNK7WebCore5Range11startOffsetERi
</span><ins>+__ZNK7WebCore5Range12boundingRectEv
</ins><span class="cx"> __ZNK7WebCore5Range12endContainerERi
</span><span class="cx"> __ZNK7WebCore5Range12pastLastNodeEv
</span><span class="cx"> __ZNK7WebCore5Range14startContainerERi
</span><span class="lines">@@ -2326,6 +2329,7 @@
</span><span class="cx"> __ZN7WebCore13endOfSentenceERKNS_15VisiblePositionE
</span><span class="cx"> __ZN7WebCore13getRawCookiesERKNS_21NetworkStorageSessionERKNS_3URLES5_RN3WTF6VectorINS_6CookieELm0ENS6_15CrashOnOverflowEEE
</span><span class="cx"> __ZN7WebCore13isStartOfLineERKNS_15VisiblePositionE
</span><ins>+__ZN7WebCore14areRangesEqualEPKNS_5RangeES2_
</ins><span class="cx"> __ZN7WebCore14DocumentLoader19setResponseMIMETypeERKN3WTF6StringE
</span><span class="cx"> __ZN7WebCore14DocumentWriter3endEv
</span><span class="cx"> __ZN7WebCore14FrameSelection13setCaretColorERKNS_5ColorE
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/ChangeLog        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -1,3 +1,67 @@
</span><ins>+2014-02-21  Enrica Casucci  &lt;enrica@apple.com&gt;
+
+        Support WebSelections in WK2 on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=127015
+        &lt;rdar://problem/15211964&gt;
+
+        Reviewed by Benjamin Poulain.
+
+        This is the remaining work on block selections for iOS in WK2.
+        Once a block selection has been created with a long press gesture
+        on a selectable area, we can interact with it by touching the four
+        handles at the top, right, bottom and left side of the selection box.
+        Expanding or shrinking a block selection requires finding the next/previous
+        block in the direction of the movement, depending on the handle we
+        are interacting with.
+        Every time a new block is selected, we compute the thresholds required
+        to trigger another block change. The thresholds are sent back to the
+        UIProcess that will use this information to decide when to activate
+        the new selection, either bigger or smaller.
+        This patch also fixes a bug in selectWithTwoTouches where the points
+        were not mapped to the active frame.
+
+        * Shared/ios/WKGestureTypes.h:
+        * UIProcess/API/ios/PageClientImplIOS.h:
+        * UIProcess/API/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::didUpdateBlockSelectionWithTouches):
+        * UIProcess/API/ios/WKContentView.mm:
+        (-[WKContentView _didUpdateBlockSelectionWithTouches:withFlags:growThreshold:shrinkThreshold:]):
+        * UIProcess/API/ios/WKContentViewInternal.h:
+        * UIProcess/API/ios/WKInteractionView.h:
+        * UIProcess/API/ios/WKInteractionView.mm:
+        (-[WKInteractionView hasSelectablePositionAtPoint:]):
+        (-[WKInteractionView clearSelection]):
+        (toWKHandlePosition):
+        (-[WKInteractionView _didUpdateBlockSelectionWithTouches:WebKit::withFlags:WebKit::growThreshold:shrinkThreshold:]):
+        (-[WKInteractionView changeBlockSelectionWithTouchAt:withSelectionTouch:forHandle:]):
+        * UIProcess/PageClient.h:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::updateBlockSelectionWithTouches):
+        (WebKit::WebPageProxy::didUpdateBlockSelectionWithTouches):
+        * WebProcess/WebPage/WebPage.cpp:
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::rangeForWebSelectionAtPosition):
+        (WebKit::WebPage::rangeForBlockAtPoint):
+        (WebKit::WebPage::selectWithGesture):
+        (WebKit::distanceBetweenRectsForPosition):
+        (WebKit::rectsEssentiallyTheSame):
+        (WebKit::containsRange):
+        (WebKit::unionDOMRanges):
+        (WebKit::computeEdgeCenter):
+        (WebKit::WebPage::expandedRangeFromHandle):
+        (WebKit::WebPage::contractedRangeFromHandle):
+        (WebKit::WebPage::computeExpandAndShrinkThresholdsForHandle):
+        (WebKit::shouldExpand):
+        (WebKit::WebPage::changeBlockSelection):
+        (WebKit::WebPage::updateBlockSelectionWithTouches):
+        (WebKit::WebPage::clearSelection):
+        (WebKit::WebPage::selectWithTwoTouches):
+        (WebKit::WebPage::getPositionInformation):
+
</ins><span class="cx"> 2014-02-21  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Make sure to invoke the completion handler for JS alerts
</span></span></pre></div>
<a id="trunkSourceWebKit2SharediosWKGestureTypesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Shared/ios/WKGestureTypes.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Shared/ios/WKGestureTypes.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/Shared/ios/WKGestureTypes.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -75,6 +75,12 @@
</span><span class="cx">     WKIsBlockSelection = 2
</span><span class="cx"> } WKSelectionFlags;
</span><span class="cx"> 
</span><ins>+typedef enum {
+    WKHandleTop,
+    WKHandleRight,
+    WKHandleBottom,
+    WKHandleLeft
+} WKHandlePosition;
</ins><span class="cx"> } // namespace WebKit
</span><span class="cx"> 
</span><span class="cx"> #endif // WKGestureTypes_h
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosPageClientImplIOSh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -110,6 +110,7 @@
</span><span class="cx">     virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&amp;, bool isCharEvent) override;
</span><span class="cx">     virtual void positionInformationDidChange(const InteractionInformationAtPosition&amp;);
</span><span class="cx">     virtual void saveImageToLibrary(PassRefPtr&lt;WebCore::SharedBuffer&gt;);
</span><ins>+    virtual void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold);
</ins><span class="cx"> 
</span><span class="cx">     // Auxiliary Client Creation
</span><span class="cx"> #if ENABLE(FULLSCREEN_API)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosPageClientImplIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.mm (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.mm        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.mm        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -356,6 +356,11 @@
</span><span class="cx">     [m_view _stopAssistingNode];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void PageClientImpl::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
+{
+    [m_view _didUpdateBlockSelectionWithTouch:(WKSelectionTouch)touch withFlags:(WKSelectionFlags)flags growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
</ins><span class="cx"> #if ENABLE(FULLSCREEN_API)
</span><span class="cx"> 
</span><span class="cx"> WebFullScreenManagerProxyClient&amp; PageClientImpl::fullScreenManagerProxyClient()
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosWKContentViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/WKContentView.mm (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/WKContentView.mm        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/WKContentView.mm        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -298,6 +298,11 @@
</span><span class="cx">     [_interactionView _selectionChanged];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)_didUpdateBlockSelectionWithTouch:(WKSelectionTouch)touch withFlags:(WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold
+{
+    [_interactionView _didUpdateBlockSelectionWithTouch:touch withFlags:flags growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
</ins><span class="cx"> - (BOOL)_interpretKeyEvent:(WebIOSEvent *)theEvent isCharEvent:(BOOL)isCharEvent
</span><span class="cx"> {
</span><span class="cx">     return [_interactionView _interpretKeyEvent:theEvent isCharEvent:isCharEvent];
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosWKContentViewInternalh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/WKContentViewInternal.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/WKContentViewInternal.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/WKContentViewInternal.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -24,6 +24,7 @@
</span><span class="cx">  */
</span><span class="cx"> 
</span><span class="cx"> #import &quot;WKContentView.h&quot;
</span><ins>+#import &quot;WKGestureTypes.h&quot;
</ins><span class="cx"> #import &lt;wtf/Forward.h&gt;
</span><span class="cx"> #import &lt;wtf/RetainPtr.h&gt;
</span><span class="cx"> #import &lt;wtf/Vector.h&gt;
</span><span class="lines">@@ -71,6 +72,7 @@
</span><span class="cx"> - (BOOL)_interpretKeyEvent:(WebIOSEvent *)theEvent isCharEvent:(BOOL)isCharEvent;
</span><span class="cx"> - (void)_positionInformationDidChange:(const WebKit::InteractionInformationAtPosition&amp;)info;
</span><span class="cx"> - (void)_decidePolicyForGeolocationRequestFromOrigin:(WebKit::WebSecurityOrigin&amp;)origin frame:(WebKit::WebFrameProxy&amp;)frame request:(WebKit::GeolocationPermissionRequestProxy&amp;)permissionRequest;
</span><ins>+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold;
</ins><span class="cx"> 
</span><span class="cx"> - (RetainPtr&lt;CGImageRef&gt;)_takeViewSnapshot;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosWKInteractionViewh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -70,5 +70,6 @@
</span><span class="cx"> - (void)_willStartScrollingOrZooming;
</span><span class="cx"> - (void)_willStartUserTriggeredScrollingOrZooming;
</span><span class="cx"> - (void)_didEndScrollingOrZooming;
</span><ins>+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold;
</ins><span class="cx"> @property (readonly, nonatomic) WebKit::InteractionInformationAtPosition positionInformation;
</span><span class="cx"> @end
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPIiosWKInteractionViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.mm (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.mm        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/API/ios/WKInteractionView.mm        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -564,6 +564,7 @@
</span><span class="cx"> {
</span><span class="cx">     [self ensurePositionInformationIsUpToDate:point];
</span><span class="cx">     // FIXME: This check needs to be extended to include other elements.
</span><ins>+    // FIXME: We need to reject positions that will lead to a very large selection.
</ins><span class="cx">     return _positionInformation.clickableElementName != &quot;IMG&quot; &amp;&amp; _positionInformation.clickableElementName != &quot;A&quot; &amp;&amp; !_positionInformation.selectionRects.isEmpty();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -693,6 +694,11 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)clearSelection
+{
+    _page-&gt;clearSelection();
+}
+
</ins><span class="cx"> - (void)_positionInformationDidChange:(const InteractionInformationAtPosition&amp;)info
</span><span class="cx"> {
</span><span class="cx">     _positionInformation = info;
</span><span class="lines">@@ -1105,6 +1111,20 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static inline WKHandlePosition toWKHandlePosition(UIWKHandlePosition position)
+{
+    switch (position) {
+    case UIWKHandleTop:
+        return WKHandleTop;
+    case UIWKHandleRight:
+        return WKHandleRight;
+    case UIWKHandleBottom:
+        return WKHandleBottom;
+    case UIWKHandleLeft:
+        return WKHandleLeft;
+    }
+}
+
</ins><span class="cx"> static void selectionChangedWithGesture(bool error, WKInteractionView *view, const WebCore::IntPoint&amp; point, uint32_t gestureType, uint32_t gestureState, uint32_t flags)
</span><span class="cx"> {
</span><span class="cx">     if (error) {
</span><span class="lines">@@ -1129,6 +1149,11 @@
</span><span class="cx">         [(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((WKSelectionTouch)touch)];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold
+{
+    [_webSelectionAssistant blockSelectionChangedWithTouch:toUIWKSelectionTouch((WKSelectionTouch)touch) withFlags:toUIWKSelectionFlags((WKSelectionFlags)flags) growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
</ins><span class="cx"> - (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(UIWKGestureType)gestureType withState:(UIGestureRecognizerState)state
</span><span class="cx"> {
</span><span class="cx">     _page-&gt;selectWithGesture(WebCore::IntPoint(point), CharacterGranularity, toWKGestureType(gestureType), toWKGestureRecognizerState(state), GestureCallback::create([self](bool error, const WebCore::IntPoint&amp; point, uint32_t gestureType, uint32_t gestureState, uint32_t flags) {
</span><span class="lines">@@ -1150,6 +1175,11 @@
</span><span class="cx">     }));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)changeBlockSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch forHandle:(UIWKHandlePosition)handle
+{
+    _page-&gt;updateBlockSelectionWithTouch(WebCore::IntPoint(point), toWKSelectionTouch(touch), toWKHandlePosition(handle));
+}
+
</ins><span class="cx"> - (WKAutoCorrectionData *)autocorrectionData
</span><span class="cx"> {
</span><span class="cx">     return &amp;_autocorrectionData;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessPageClienth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/PageClient.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/PageClient.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/PageClient.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -249,6 +249,7 @@
</span><span class="cx">     virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&amp;, bool isCharEvent) = 0;
</span><span class="cx">     virtual void positionInformationDidChange(const InteractionInformationAtPosition&amp;) = 0;
</span><span class="cx">     virtual void saveImageToLibrary(PassRefPtr&lt;WebCore::SharedBuffer&gt;) = 0;
</span><ins>+    virtual void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold) = 0;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     // Auxiliary Client Creation
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -458,6 +458,7 @@
</span><span class="cx">     void selectWithGesture(const WebCore::IntPoint, WebCore::TextGranularity, uint32_t gestureType, uint32_t gestureState, PassRefPtr&lt;GestureCallback&gt;);
</span><span class="cx">     void updateSelectionWithTouches(const WebCore::IntPoint, uint32_t touches, bool baseIsStart, PassRefPtr&lt;TouchesCallback&gt;);
</span><span class="cx">     void selectWithTwoTouches(const WebCore::IntPoint from, const WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, PassRefPtr&lt;GestureCallback&gt;);
</span><ins>+    void updateBlockSelectionWithTouch(const WebCore::IntPoint, uint32_t touch, uint32_t handlePosition);
</ins><span class="cx">     void extendSelection(WebCore::TextGranularity);
</span><span class="cx">     void requestAutocorrectionData(const String&amp; textForAutocorrection, PassRefPtr&lt;AutocorrectionDataCallback&gt;);
</span><span class="cx">     void applyAutocorrection(const String&amp; correction, const String&amp; originalText, PassRefPtr&lt;StringCallback&gt;);
</span><span class="lines">@@ -470,6 +471,7 @@
</span><span class="cx">     void stopInteraction();
</span><span class="cx">     void performActionOnElement(uint32_t action);
</span><span class="cx">     void saveImageToLibrary(const SharedMemory::Handle&amp; imageHandle, uint64_t imageSize);
</span><ins>+    void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     const EditorState&amp; editorState() const { return m_editorState; }
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessWebPageProxymessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/WebPageProxy.messages.in        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -156,6 +156,7 @@
</span><span class="cx">     InterpretKeyEvent(WebKit::EditorState state, bool isCharEvent) -&gt; (bool handled)
</span><span class="cx">     DidReceivePositionInformation(WebKit::InteractionInformationAtPosition information)
</span><span class="cx">     SaveImageToLibrary(WebKit::SharedMemory::Handle handle, uint64_t size)
</span><ins>+    DidUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
</ins><span class="cx"> #endif
</span><span class="cx"> #if PLATFORM(GTK)
</span><span class="cx">     PrintFinishedCallback(WebCore::ResourceError error, uint64_t callbackID)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWebPageProxyIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -326,6 +326,11 @@
</span><span class="cx">     m_process-&gt;send(Messages::WebPage::SelectWithTwoTouches(from, to, gestureType, gestureState, callbackID), m_pageID);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPageProxy::updateBlockSelectionWithTouch(const WebCore::IntPoint point, uint32_t touch, uint32_t handlePosition)
+{
+    m_process-&gt;send(Messages::WebPage::UpdateBlockSelectionWithTouch(point, touch, handlePosition), m_pageID);
+}
+
</ins><span class="cx"> void WebPageProxy::didReceivePositionInformation(const InteractionInformationAtPosition&amp; info)
</span><span class="cx"> {
</span><span class="cx">     m_pageClient.positionInformationDidChange(info);
</span><span class="lines">@@ -363,6 +368,11 @@
</span><span class="cx">     m_pageClient.saveImageToLibrary(buffer);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPageProxy::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
+{
+    m_pageClient.didUpdateBlockSelectionWithTouch(touch, flags, growThreshold, shrinkThreshold);
+}
+
</ins><span class="cx"> void WebPageProxy::notifyRevealedSelection()
</span><span class="cx"> {
</span><span class="cx">     m_pageClient.selectionDidChange();
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.cpp        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -3041,10 +3041,12 @@
</span><span class="cx">     return frame-&gt;editor().replaceSelectionWithText(text, selectReplacement, smartReplace);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if !PLATFORM(IOS)
</ins><span class="cx"> void WebPage::clearSelection()
</span><span class="cx"> {
</span><span class="cx">     m_page-&gt;focusController().focusedOrMainFrame().selection().clear();
</span><span class="cx"> }
</span><ins>+#endif
</ins><span class="cx"> 
</span><span class="cx"> void WebPage::updateMainFrameScrollOffsetPinning()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPageh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.h        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -438,6 +438,7 @@
</span><span class="cx">     void blurAssistedNode();
</span><span class="cx">     void selectWithGesture(const WebCore::IntPoint&amp;, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID);
</span><span class="cx">     void updateSelectionWithTouches(const WebCore::IntPoint&amp; point, uint32_t touches, bool baseIsStart, uint64_t callbackID);
</span><ins>+    void updateBlockSelectionWithTouch(const WebCore::IntPoint&amp;, uint32_t touch, uint32_t handlePosition);
</ins><span class="cx">     void selectWithTwoTouches(const WebCore::IntPoint&amp; from, const WebCore::IntPoint&amp; to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID);
</span><span class="cx">     void extendSelection(uint32_t granularity);
</span><span class="cx">     void elementDidFocus(WebCore::Node*);
</span><span class="lines">@@ -735,6 +736,13 @@
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     static void convertSelectionRectsToRootView(WebCore::FrameView*, Vector&lt;WebCore::SelectionRect&gt;&amp;);
</span><span class="cx">     PassRefPtr&lt;WebCore::Range&gt; rangeForWebSelectionAtPosition(const WebCore::IntPoint&amp;, const WebCore::VisiblePosition&amp;, WKSelectionFlags&amp;);
</span><ins>+    PassRefPtr&lt;WebCore::Range&gt; rangeForBlockAtPoint(const WebCore::IntPoint&amp;);
+    void computeExpandAndShrinkThresholdsForHandle(const WebCore::IntPoint&amp;, WKHandlePosition, float&amp; growThreshold, float&amp; shrinkThreshold);
+    PassRefPtr&lt;WebCore::Range&gt; changeBlockSelection(const WebCore::IntPoint&amp;, WKHandlePosition, float&amp; growThreshold, float&amp; shrinkThreshold, WKSelectionFlags&amp;);
+    PassRefPtr&lt;WebCore::Range&gt; expandedRangeFromHandle(WebCore::Range*, WKHandlePosition);
+    PassRefPtr&lt;WebCore::Range&gt; contractedRangeFromHandle(WebCore::Range* currentRange, WKHandlePosition, WKSelectionFlags&amp;);
+
+    RefPtr&lt;WebCore::Range&gt; m_currentBlockSelection;
</ins><span class="cx"> #endif
</span><span class="cx"> #if !PLATFORM(COCOA)
</span><span class="cx">     static const char* interpretKeyEvent(const WebCore::KeyboardEvent*);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageWebPagemessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/WebProcess/WebPage/WebPage.messages.in        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx">     BlurAssistedNode()
</span><span class="cx">     SelectWithGesture(WebCore::IntPoint point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
</span><span class="cx">     UpdateSelectionWithTouches(WebCore::IntPoint point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
</span><ins>+    UpdateBlockSelectionWithTouch(WebCore::IntPoint point, uint32_t touch, uint32_t handlePosition)
</ins><span class="cx">     SelectWithTwoTouches(WebCore::IntPoint from, WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
</span><span class="cx">     ExtendSelection(uint32_t granularity)
</span><span class="cx">     RequestAutocorrectionData(String textForAutocorrection, uint64_t callbackID)
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageiosWebPageIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm (164496 => 164497)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-02-21 21:52:47 UTC (rev 164496)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm        2014-02-21 21:56:14 UTC (rev 164497)
</span><span class="lines">@@ -438,11 +438,10 @@
</span><span class="cx">     Node* currentNode = result.innerNode();
</span><span class="cx">     RefPtr&lt;Range&gt; range;
</span><span class="cx">     IntRect boundingRect;
</span><del>-    ExceptionCode ec;
</del><span class="cx"> 
</span><span class="cx">     if (currentNode-&gt;isTextNode()) {
</span><span class="cx">         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
</span><del>-        if (!range || range-&gt;collapsed(ec))
</del><ins>+        if (!range || range-&gt;collapsed(ASSERT_NO_EXCEPTION))
</ins><span class="cx">             range = Range::create(currentNode-&gt;document(), position, position);
</span><span class="cx">         if (!range)
</span><span class="cx">             return nullptr;
</span><span class="lines">@@ -461,7 +460,7 @@
</span><span class="cx">         if (boundingRect.width() &gt; m_blockSelectionDesiredSize.width() &amp;&amp; boundingRect.height() &gt; m_blockSelectionDesiredSize.height())
</span><span class="cx">             return wordRangeFromPosition(position);
</span><span class="cx"> 
</span><del>-        currentNode = range-&gt;commonAncestorContainer(ec);
</del><ins>+        currentNode = range-&gt;commonAncestorContainer(ASSERT_NO_EXCEPTION);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!currentNode-&gt;isElementNode())
</span><span class="lines">@@ -482,15 +481,39 @@
</span><span class="cx">     RenderObject* renderer = bestChoice-&gt;renderer();
</span><span class="cx">     if (renderer &amp;&amp; renderer-&gt;childrenInline() &amp;&amp; (renderer-&gt;isRenderBlock() &amp;&amp; toRenderBlock(renderer)-&gt;inlineElementContinuation() == nil) &amp;&amp; !renderer-&gt;isTable()) {
</span><span class="cx">         range = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionBackward);
</span><del>-        if (range &amp;&amp; !range-&gt;collapsed(ec))
</del><ins>+        if (range &amp;&amp; !range-&gt;collapsed(ASSERT_NO_EXCEPTION))
</ins><span class="cx">             return range;
</span><span class="cx">     }
</span><span class="cx">     flags = WKIsBlockSelection;
</span><span class="cx">     range = Range::create(bestChoice-&gt;document());
</span><del>-    range-&gt;selectNode(bestChoice, ec);
</del><ins>+    range-&gt;selectNodeContents(bestChoice, ASSERT_NO_EXCEPTION);
</ins><span class="cx">     return range;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+PassRefPtr&lt;Range&gt; WebPage::rangeForBlockAtPoint(const IntPoint&amp; point)
+{
+    HitTestResult result = m_page-&gt;mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
+
+    Node* currentNode = result.innerNode();
+    RefPtr&lt;Range&gt; range;
+
+    if (currentNode-&gt;isTextNode()) {
+        range = enclosingTextUnitOfGranularity(m_page-&gt;focusController().focusedOrMainFrame().visiblePositionForPoint(point), ParagraphGranularity, DirectionForward);
+        if (range &amp;&amp; !range-&gt;collapsed(ASSERT_NO_EXCEPTION))
+            return range;
+    }
+
+    if (!currentNode-&gt;isElementNode())
+        currentNode = currentNode-&gt;parentElement();
+
+    if (!currentNode)
+        return nullptr;
+
+    range = Range::create(currentNode-&gt;document());
+    range-&gt;selectNodeContents(currentNode, ASSERT_NO_EXCEPTION);
+    return range;
+}
+
</ins><span class="cx"> void WebPage::selectWithGesture(const IntPoint&amp; point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="lines">@@ -504,6 +527,7 @@
</span><span class="cx">     }
</span><span class="cx">     RefPtr&lt;Range&gt; range;
</span><span class="cx">     WKSelectionFlags flags = WKNone;
</span><ins>+    WKGestureRecognizerState wkGestureState = static_cast&lt;WKGestureRecognizerState&gt;(gestureState);
</ins><span class="cx">     switch (static_cast&lt;WKGestureType&gt;(gestureType)) {
</span><span class="cx">     case WKGestureOneFingerTap:
</span><span class="cx">     {
</span><span class="lines">@@ -543,20 +567,17 @@
</span><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     case WKGestureTapAndAHalf:
</span><del>-        switch (static_cast&lt;WKGestureRecognizerState&gt;(gestureState)) {
</del><ins>+        switch (wkGestureState) {
</ins><span class="cx">         case WKGestureRecognizerStateBegan:
</span><span class="cx">             range = wordRangeFromPosition(position);
</span><span class="cx">             m_currentWordRange = Range::create(*frame.document(), range-&gt;startPosition(), range-&gt;endPosition());
</span><span class="cx">             break;
</span><span class="cx">         case WKGestureRecognizerStateChanged:
</span><del>-        {
</del><span class="cx">             range = Range::create(*frame.document(), m_currentWordRange-&gt;startPosition(), m_currentWordRange-&gt;endPosition());
</span><del>-            ExceptionCode ec;
</del><span class="cx">             if (position &lt; range-&gt;startPosition())
</span><del>-                range-&gt;setStart(position.deepEquivalent(), ec);
</del><ins>+                range-&gt;setStart(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
</ins><span class="cx">             if (position &gt; range-&gt;endPosition())
</span><del>-                range-&gt;setEnd(position.deepEquivalent(), ec);
-        }
</del><ins>+                range-&gt;setEnd(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
</ins><span class="cx">             break;
</span><span class="cx">         case WKGestureRecognizerStateEnded:
</span><span class="cx">         case WKGestureRecognizerStateCancelled:
</span><span class="lines">@@ -594,11 +615,14 @@
</span><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     case WKGestureMakeWebSelection:
</span><del>-        if (static_cast&lt;WKGestureRecognizerState&gt;(gestureState) == WKGestureRecognizerStateBegan) {
</del><ins>+        if (wkGestureState == WKGestureRecognizerStateBegan) {
</ins><span class="cx">             m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
</span><span class="cx">             m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
</span><ins>+            m_currentBlockSelection = nullptr;
</ins><span class="cx">         }
</span><span class="cx">         range = rangeForWebSelectionAtPosition(point, position, flags);
</span><ins>+        if (wkGestureState == WKGestureRecognizerStateEnded &amp;&amp; flags &amp; WKIsBlockSelection)
+            m_currentBlockSelection = range;
</ins><span class="cx">         break;
</span><span class="cx"> 
</span><span class="cx">     default:
</span><span class="lines">@@ -689,6 +713,415 @@
</span><span class="cx">     return (base &lt; extent) ? Range::create(*frame-&gt;document(), base, extent) : Range::create(*frame-&gt;document(), extent, base);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static const int maxHitTests = 10;
+
+static inline float distanceBetweenRectsForPosition(IntRect&amp; first, IntRect&amp; second, WKHandlePosition handlePosition)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return abs(first.y() - second.y());
+    case WKHandleRight:
+        return abs(first.maxX() - second.maxX());
+    case WKHandleBottom:
+        return abs(first.maxY() - second.maxY());
+    case WKHandleLeft:
+        return abs(first.x() - second.x());
+    }
+}
+
+static inline bool rectsEssentiallyTheSame(IntRect&amp; first, IntRect&amp; second, float allowablePercentDifference)
+{
+    const float minMagnitudeRatio = 1.0 - allowablePercentDifference;
+    const float maxDisplacementRatio = allowablePercentDifference;
+
+    float xOriginShiftRatio = abs(first.x() - second.x())/std::min(first.width(), second.width());
+    float yOriginShiftRatio = abs(first.y() - second.y())/std::min(first.height(), second.height());
+
+    float widthRatio = std::min(first.width() / second.width(), second.width() / first.width());
+    float heightRatio = std::min(first.height() / second.height(), second.height() / first.height());
+    return ((widthRatio &gt; minMagnitudeRatio &amp;&amp; xOriginShiftRatio &lt; maxDisplacementRatio)
+        &amp;&amp; (heightRatio &gt; minMagnitudeRatio &amp;&amp; yOriginShiftRatio &lt; maxDisplacementRatio));
+}
+
+static inline bool containsRange(Range* first, Range* second)
+{
+    if (!first || !second)
+        return false;
+    return (first-&gt;commonAncestorContainer(ASSERT_NO_EXCEPTION)-&gt;ownerDocument() == second-&gt;commonAncestorContainer(ASSERT_NO_EXCEPTION)-&gt;ownerDocument()
+        &amp;&amp; first-&gt;compareBoundaryPoints(Range::START_TO_START, second, ASSERT_NO_EXCEPTION) &lt;= 0
+        &amp;&amp; first-&gt;compareBoundaryPoints(Range::END_TO_END, second, ASSERT_NO_EXCEPTION) &gt;= 0);
+}
+
+static inline RefPtr&lt;Range&gt; unionDOMRanges(Range* rangeA, Range* rangeB)
+{
+    if (!rangeB)
+        return rangeA;
+    if (!rangeA)
+        return rangeB;
+
+    Range* start = rangeA-&gt;compareBoundaryPoints(Range::START_TO_START, rangeB, ASSERT_NO_EXCEPTION) &lt;= 0 ? rangeA : rangeB;
+    Range* end = rangeA-&gt;compareBoundaryPoints(Range::END_TO_END, rangeB, ASSERT_NO_EXCEPTION) &lt;= 0 ? rangeB : rangeA;
+
+    return Range::create(rangeA-&gt;ownerDocument(), start-&gt;startContainer(), start-&gt;startOffset(), end-&gt;endContainer(), end-&gt;endOffset());
+}
+
+static inline IntPoint computeEdgeCenter(const IntRect&amp; box, WKHandlePosition handlePosition)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return IntPoint(box.x() + box.width() / 2, box.y());
+    case WKHandleRight:
+        return IntPoint(box.maxX(), box.y() + box.height() / 2);
+    case WKHandleBottom:
+        return IntPoint(box.x() + box.width() / 2, box.maxY());
+    case WKHandleLeft:
+        return IntPoint(box.x(), box.y() + box.height() / 2);
+    }
+}
+
+PassRefPtr&lt;Range&gt; WebPage::expandedRangeFromHandle(Range* currentRange, WKHandlePosition handlePosition)
+{
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when &lt;rdar://problem/16063723&gt; is fixed.
+    IntRect currentBox = currentRange-&gt;boundingBox();
+    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
+    static const float maxDistance = 1000;
+    const float multiple = powf(maxDistance, 1.0/(maxHitTests - 1));
+    float distance = 1;
+
+    RefPtr&lt;Range&gt; bestRange;
+    IntRect bestRect;
+
+    while (distance &lt; maxDistance) {
+        if (bestRange) {
+            if (distanceBetweenRectsForPosition(bestRect, currentBox, handlePosition) &lt; distance) {
+                // Break early, we're unlikely to do any better.
+                break;
+            }
+        }
+
+        IntPoint testPoint = edgeCenter;
+        switch (handlePosition) {
+        case WKHandleTop:
+            testPoint.move(0, -distance);
+            break;
+        case WKHandleRight:
+            testPoint.move(distance, 0);
+            break;
+        case WKHandleBottom:
+            testPoint.move(0, distance);
+            break;
+        case WKHandleLeft:
+            testPoint.move(-distance, 0);
+            break;
+        }
+
+        RefPtr&lt;Range&gt; newRange;
+        RefPtr&lt;Range&gt; rangeAtPosition = rangeForBlockAtPoint(testPoint);
+        if (containsRange(rangeAtPosition.get(), currentRange))
+            newRange = rangeAtPosition;
+        else if (containsRange(currentRange, rangeAtPosition.get()))
+            newRange = currentRange;
+        else
+            newRange = unionDOMRanges(currentRange, rangeAtPosition.get());
+
+        IntRect copyRect = newRange-&gt;boundingBox();
+
+        // Is it different and bigger than the current?
+        bool isBetterChoice = !(rectsEssentiallyTheSame(copyRect, currentBox, .05));
+        if (isBetterChoice) {
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() &gt; currentBox.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                isBetterChoice = (copyRect.width() &gt; currentBox.width());
+                break;
+            }
+
+        }
+
+        if (bestRange &amp;&amp; isBetterChoice) {
+            // Furtherore, is it smaller than the best we've found so far?
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() &lt; bestRect.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                isBetterChoice = (copyRect.width() &lt; bestRect.width());
+                break;
+            }
+        }
+
+        if (isBetterChoice) {
+            bestRange = newRange;
+            bestRect = copyRect;
+        }
+
+        distance = ceilf(distance * multiple);
+    }
+
+    if (bestRange)
+        return bestRange;
+
+    return currentRange;
+}
+
+PassRefPtr&lt;Range&gt; WebPage::contractedRangeFromHandle(Range* currentRange, WKHandlePosition handlePosition, WKSelectionFlags&amp; flags)
+{
+    // Shrinking with a base and extent will always give better results. If we only have a single element,
+    // see if we can break that down to a base and extent. Shrinking base and extent is comparatively straightforward.
+    // Shrinking down to another element is unlikely to move just one edge, but we can try that as a fallback.
+
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when &lt;rdar://problem/16063723&gt; is fixed.
+    IntRect currentBox = currentRange-&gt;boundingBox();
+    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
+    flags = WKIsBlockSelection;
+
+    float maxDistance;
+
+    switch (handlePosition) {
+    case WKHandleTop:
+    case WKHandleBottom:
+        maxDistance = currentBox.height();
+        break;
+    case WKHandleRight:
+    case WKHandleLeft:
+        maxDistance = currentBox.width();
+        break;
+    }
+
+    const float multiple = powf(maxDistance - 1, 1.0/(maxHitTests - 1));
+    float distance = 1;
+    RefPtr&lt;Range&gt; bestRange;
+    IntRect bestRect;
+
+    while (distance &lt; maxDistance) {
+        if (bestRange) {
+            float shrankDistance;
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                shrankDistance = abs(currentBox.height() - bestRect.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                shrankDistance = abs(currentBox.width() - bestRect.width());
+                break;
+            }
+            if (shrankDistance &gt; distance) {
+                // Certainly not going to do any better than that.
+                break;
+            }
+        }
+
+        IntPoint testPoint = edgeCenter;
+        switch (handlePosition) {
+        case WKHandleTop:
+            testPoint.move(0, distance);
+            break;
+        case WKHandleRight:
+            testPoint.move(-distance, 0);
+            break;
+        case WKHandleBottom:
+            testPoint.move(0, -distance);
+            break;
+        case WKHandleLeft:
+            testPoint.move(distance, 0);
+            break;
+        }
+
+        RefPtr&lt;Range&gt; newRange = rangeForBlockAtPoint(testPoint);
+        if (handlePosition == WKHandleTop || handlePosition == WKHandleLeft)
+            newRange = Range::create(newRange-&gt;startContainer()-&gt;document(), newRange-&gt;startPosition(), currentRange-&gt;endPosition());
+        else
+            newRange = Range::create(newRange-&gt;startContainer()-&gt;document(), currentRange-&gt;startPosition(), newRange-&gt;endPosition());
+
+        IntRect copyRect = newRange-&gt;boundingBox();
+        bool isBetterChoice;
+        switch (handlePosition) {
+        case WKHandleTop:
+        case WKHandleBottom:
+            isBetterChoice = (copyRect.height() &lt; currentBox.height());
+            break;
+        case WKHandleLeft:
+        case WKHandleRight:
+            isBetterChoice = (copyRect.width() &gt; bestRect.width());
+            break;
+        }
+
+        isBetterChoice = isBetterChoice &amp;&amp; !areRangesEqual(newRange.get(), currentRange);
+        if (bestRange &amp;&amp; isBetterChoice) {
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() &gt; bestRect.height());
+                break;
+            case WKHandleLeft:
+            case WKHandleRight:
+                isBetterChoice = (copyRect.width() &gt; bestRect.width());
+                break;
+            }
+        }
+        if (isBetterChoice) {
+            bestRange = newRange;
+            bestRect = copyRect;
+        }
+
+        distance *= multiple;
+    }
+
+    // If we can shrink down to text only, the only reason we wouldn't is that
+    // there are multiple sub-element blocks beneath us.  If we didn't find
+    // multiple sub-element blocks, don't shrink to a sub-element block.
+    if (!bestRange) {
+        bestRange = currentRange;
+        Node* node = currentRange-&gt;commonAncestorContainer(ASSERT_NO_EXCEPTION);
+        if (!node-&gt;isElementNode())
+            node = node-&gt;parentElement();
+
+        RenderObject* renderer = node-&gt;renderer();
+        if (renderer &amp;&amp; renderer-&gt;childrenInline() &amp;&amp; (renderer-&gt;isRenderBlock() &amp;&amp; !toRenderBlock(renderer)-&gt;inlineElementContinuation()) &amp;&amp; !renderer-&gt;isTable()) {
+            flags = WKNone;
+        }
+    }
+
+    return bestRange;
+}
+
+void WebPage::computeExpandAndShrinkThresholdsForHandle(const IntPoint&amp; point, WKHandlePosition handlePosition, float&amp; growThreshold, float&amp; shrinkThreshold)
+{
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+    RefPtr&lt;Range&gt; currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
+    ASSERT(currentRange);
+
+    RefPtr&lt;Range&gt; expandedRange = expandedRangeFromHandle(currentRange.get(), handlePosition);
+    WKSelectionFlags flags;
+    RefPtr&lt;Range&gt; contractedRange = contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
+
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when &lt;rdar://problem/16063723&gt; is fixed.
+    IntRect currentBounds = currentRange-&gt;boundingBox();
+    IntRect expandedBounds = expandedRange-&gt;boundingBox();
+    IntRect contractedBounds = contractedRange-&gt;boundingBox();
+
+    float current;
+    float expanded;
+    float contracted;
+    float maxThreshold;
+    float minThreshold;
+
+    switch (handlePosition) {
+    case WKHandleTop: {
+        current = currentBounds.y();
+        expanded = expandedBounds.y();
+        contracted = contractedBounds.y();
+        maxThreshold = FLT_MIN;
+        minThreshold = FLT_MAX;
+        break;
+    }
+    case WKHandleRight: {
+        current = currentBounds.maxX();
+        expanded = expandedBounds.maxX();
+        contracted = contractedBounds.maxX();
+        maxThreshold = FLT_MAX;
+        minThreshold = FLT_MIN;
+        break;
+    }
+    case WKHandleBottom: {
+        current = currentBounds.maxY();
+        expanded = expandedBounds.maxY();
+        contracted = contractedBounds.maxY();
+        maxThreshold = FLT_MAX;
+        minThreshold = FLT_MIN;
+        break;
+    }
+    case WKHandleLeft: {
+        current = currentBounds.x();
+        expanded = expandedBounds.x();
+        contracted = contractedBounds.x();
+        maxThreshold = FLT_MIN;
+        minThreshold = FLT_MAX;
+        break;
+    }
+    }
+
+    static const float fractionToGrow = 0.3;
+
+    growThreshold = current + (expanded - current) * fractionToGrow;
+    shrinkThreshold = current + (contracted - current) * (1 - fractionToGrow);
+    if (areRangesEqual(expandedRange.get(), currentRange.get()))
+        growThreshold = maxThreshold;
+
+    if ((flags &amp; WKIsBlockSelection) &amp;&amp; areRangesEqual(contractedRange.get(), currentRange.get()))
+        shrinkThreshold = minThreshold;
+}
+
+static inline bool shouldExpand(WKHandlePosition handlePosition, const IntRect&amp; rect, const IntPoint&amp; point)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return (point.y() &lt; rect.y());
+    case WKHandleLeft:
+        return (point.x() &lt; rect.x());
+    case WKHandleRight:
+        return (point.x() &gt; rect.maxX());
+    case WKHandleBottom:
+        return (point.y() &gt; rect.maxY());
+    }
+}
+
+PassRefPtr&lt;WebCore::Range&gt; WebPage::changeBlockSelection(const IntPoint&amp; point, WKHandlePosition handlePosition, float&amp; growThreshold, float&amp; shrinkThreshold, WKSelectionFlags&amp; flags)
+{
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+    RefPtr&lt;Range&gt; currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when &lt;rdar://problem/16063723&gt; is fixed.
+    IntRect currentRect = currentRange-&gt;boundingBox();
+
+    RefPtr&lt;Range&gt; newRange = shouldExpand(handlePosition, currentRect, point) ? expandedRangeFromHandle(currentRange.get(), handlePosition) : contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
+
+    if (newRange) {
+        m_currentBlockSelection = newRange;
+        frame.selection().setSelectedRange(newRange.get(), VP_DEFAULT_AFFINITY, true);
+    }
+
+    computeExpandAndShrinkThresholdsForHandle(point, handlePosition, growThreshold, shrinkThreshold);
+    return newRange;
+}
+
+void WebPage::updateBlockSelectionWithTouch(const IntPoint&amp; point, uint32_t touch, uint32_t handlePosition)
+{
+    Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
+    IntPoint adjustedPoint = frame.view()-&gt;rootViewToContents(point);
+
+    float growThreshold = 0;
+    float shrinkThreshold = 0;
+    WKSelectionFlags flags = WKIsBlockSelection;
+
+    switch (static_cast&lt;WKSelectionTouch&gt;(touch)) {
+    case WKSelectionTouchStarted:
+        computeExpandAndShrinkThresholdsForHandle(adjustedPoint, static_cast&lt;WKHandlePosition&gt;(handlePosition), growThreshold, shrinkThreshold);
+        break;
+    case WKSelectionTouchEnded:
+        break;
+    case WKSelectionTouchMoved:
+        changeBlockSelection(adjustedPoint, static_cast&lt;WKHandlePosition&gt;(handlePosition), growThreshold, shrinkThreshold, flags);
+        break;
+    default:
+        return;
+    }
+
+    send(Messages::WebPageProxy::DidUpdateBlockSelectionWithTouch(touch, flags, growThreshold, shrinkThreshold));
+}
+
+void WebPage::clearSelection()
+{
+    m_currentBlockSelection = nullptr;
+    m_page-&gt;focusController().focusedOrMainFrame().selection().clear();
+}
+
</ins><span class="cx"> void WebPage::updateSelectionWithTouches(const IntPoint&amp; point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><span class="lines">@@ -736,8 +1169,8 @@
</span><span class="cx"> void WebPage::selectWithTwoTouches(const WebCore::IntPoint&amp; from, const WebCore::IntPoint&amp; to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
</span><span class="cx"> {
</span><span class="cx">     Frame&amp; frame = m_page-&gt;focusController().focusedOrMainFrame();
</span><del>-    VisiblePosition fromPosition = frame.visiblePositionForPoint(from);
-    VisiblePosition toPosition = frame.visiblePositionForPoint(to);
</del><ins>+    VisiblePosition fromPosition = frame.visiblePositionForPoint(frame.view()-&gt;rootViewToContents(from));
+    VisiblePosition toPosition = frame.visiblePositionForPoint(frame.view()-&gt;rootViewToContents(to));
</ins><span class="cx">     RefPtr&lt;Range&gt; range;
</span><span class="cx">     if (fromPosition.isNotNull() &amp;&amp; toPosition.isNotNull()) {
</span><span class="cx">         if (fromPosition &lt; toPosition)
</span><span class="lines">@@ -980,6 +1413,7 @@
</span><span class="cx">         if (hitNode) {
</span><span class="cx">             m_page-&gt;focusController().setFocusedFrame(result.innerNodeFrame());
</span><span class="cx">             info.selectionRects.append(SelectionRect(hitNode-&gt;renderer()-&gt;absoluteBoundingBoxRect(true), true, 0));
</span><ins>+            info.bounds = hitNode-&gt;renderer()-&gt;absoluteBoundingBoxRect();
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>