<!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>[218855] 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/218855">218855</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2017-06-27 17:36:31 -0700 (Tue, 27 Jun 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS DnD] Support dragging out of contenteditable areas without a prior selection
https://bugs.webkit.org/show_bug.cgi?id=173854
<rdar://problem/32236827>

Reviewed by Ryosuke Niwa and Tim Horton.

Source/WebCore:

Allows elements to be dragged from contenteditable areas for both WebKit1 and WebKit2 iOS. There are two main
changes in WebCore: move the touch point adjustment code into EventHandler::tryToBeginDataInteractionAtPoint, so
that the clientPosition specified will be adjusted to an appropriate clickable node if needed. This is necessary
because UIWebDocumentView and WKContentView no longer send adjusted points to WebCore when requesting drag
start. See <https://bugs.webkit.org/show_bug.cgi?id=173855> for a followup regarding the globalPosition and
clientPositions passed in to the MouseEvents when performing a drag or synthetic click.

Secondly, image elements in Mail's contenteditable area are not draggable unless the heuristic in
DragController::draggableElement is tweaked to not reject image dragging across the board if the
loadsImagesAutomatically setting is turned off. Instead, even if images are not automatically loaded, allow the
image drag to commence if the image renderer already has a cached image.

Test: DataInteractionTests.DragImageFromContentEditable

* page/DragController.cpp:
(WebCore::imageElementIsDraggable):
(WebCore::DragController::draggableElement):
* page/ios/EventHandlerIOS.mm:
(WebCore::EventHandler::tryToBeginDataInteractionAtPoint):

Source/WebKit/mac:

Vends some information from the DragItem passed into -[WebView _startDrag:] through the WebView as SPI for
WebKit1 clients. No behavior change with these changes alone -- see <rdar://problem/32991062> for more detail.

* WebView/WebView.mm:
(-[WebView _startDrag:]):
(-[WebView _dragSourceAction]):
(-[WebView _draggedLinkTitle]):
(-[WebView _draggedLinkURL]):
(-[WebView _draggedElementBounds]):
(-[WebView _endedDataInteraction:global:]):
* WebView/WebViewData.h:
* WebView/WebViewPrivate.h:

Source/WebKit2:

Instead of allowing a drag to occur only if a position information request discovers a clickable node, remove
the position information request entirely and just call into WebCore to try and begin the drag. Currently, the
position information request serves two purposes:
1. To adjust the hit-test location to account for nearby clickable nodes.
2. To obtain information about the content being dragged.

The first requirement is fulfilled by performing the drag location adjustment in WebCore instead (see
ChangeLogs for more detail). The second requirement is fulfilled by refactoring in
https://bugs.webkit.org/show_bug.cgi?id=173832 to fold all information relevant to starting a drag into the
DragItem struct, and then propagating the DragItem struct. The relevant information from the position
information update is now populated when the UI process receives the drag start response.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _startDrag:item:]):
(-[WKContentView computeClientAndGlobalPointsForDropSession:outClientPoint:outGlobalPoint:]):
(-[WKContentView _dragInteraction:prepareForSession:completion:]):
(-[WKContentView _api_dropInteraction:sessionDidEnter:]):
(-[WKContentView _api_dropInteraction:sessionDidUpdate:]):
(positionInformationMayStartDataInteraction): Deleted.

Tools:

Adds a new test to check that an image can be dragged out of a contenteditable and dropped.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html: Added.
* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorepageDragControllercpp">trunk/Source/WebCore/page/DragController.cpp</a></li>
<li><a href="#trunkSourceWebCorepageiosEventHandlerIOSmm">trunk/Source/WebCore/page/ios/EventHandlerIOS.mm</a></li>
<li><a href="#trunkSourceWebKitmacChangeLog">trunk/Source/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebViewmm">trunk/Source/WebKit/mac/WebView/WebView.mm</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebViewDatah">trunk/Source/WebKit/mac/WebView/WebViewData.h</a></li>
<li><a href="#trunkSourceWebKitmacWebViewWebViewPrivateh">trunk/Source/WebKit/mac/WebView/WebViewPrivate.h</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsiosDataInteractionTestsmm">trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWebKit2Cocoacontenteditableandtargethtml">trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebCore/ChangeLog      2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -1,3 +1,31 @@
</span><ins>+2017-06-27  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS DnD] Support dragging out of contenteditable areas without a prior selection
+        https://bugs.webkit.org/show_bug.cgi?id=173854
+        <rdar://problem/32236827>
+
+        Reviewed by Ryosuke Niwa and Tim Horton.
+
+        Allows elements to be dragged from contenteditable areas for both WebKit1 and WebKit2 iOS. There are two main
+        changes in WebCore: move the touch point adjustment code into EventHandler::tryToBeginDataInteractionAtPoint, so
+        that the clientPosition specified will be adjusted to an appropriate clickable node if needed. This is necessary
+        because UIWebDocumentView and WKContentView no longer send adjusted points to WebCore when requesting drag
+        start. See <https://bugs.webkit.org/show_bug.cgi?id=173855> for a followup regarding the globalPosition and
+        clientPositions passed in to the MouseEvents when performing a drag or synthetic click.
+
+        Secondly, image elements in Mail's contenteditable area are not draggable unless the heuristic in
+        DragController::draggableElement is tweaked to not reject image dragging across the board if the
+        loadsImagesAutomatically setting is turned off. Instead, even if images are not automatically loaded, allow the
+        image drag to commence if the image renderer already has a cached image.
+
+        Test: DataInteractionTests.DragImageFromContentEditable
+
+        * page/DragController.cpp:
+        (WebCore::imageElementIsDraggable):
+        (WebCore::DragController::draggableElement):
+        * page/ios/EventHandlerIOS.mm:
+        (WebCore::EventHandler::tryToBeginDataInteractionAtPoint):
+
</ins><span class="cx"> 2017-06-27  Antoine Quint  <graouts@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [Modern Media Controls] Accessibility labels should be formatted using NSDateComponentsFormatter
</span></span></pre></div>
<a id="trunkSourceWebCorepageDragControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/DragController.cpp (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/DragController.cpp     2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebCore/page/DragController.cpp        2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -713,6 +713,19 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static bool imageElementIsDraggable(const HTMLImageElement& image, const Frame& sourceFrame)
+{
+    if (sourceFrame.settings().loadsImagesAutomatically())
+        return true;
+
+    auto* renderer = image.renderer();
+    if (!is<RenderImage>(renderer))
+        return false;
+
+    auto* cachedImage = downcast<RenderImage>(*renderer).cachedImage();
+    return cachedImage && !cachedImage->errorOccurred() && cachedImage->imageForRenderer(renderer);
+}
+
</ins><span class="cx"> Element* DragController::draggableElement(const Frame* sourceFrame, Element* startElement, const IntPoint& dragOrigin, DragState& state) const
</span><span class="cx"> {
</span><span class="cx">     state.type = (sourceFrame->selection().contains(dragOrigin)) ? DragSourceActionSelection : DragSourceActionNone;
</span><span class="lines">@@ -748,7 +761,7 @@
</span><span class="cx">         if (dragMode == DRAG_AUTO) {
</span><span class="cx">             if ((m_dragSourceAction & DragSourceActionImage)
</span><span class="cx">                 && is<HTMLImageElement>(*element)
</span><del>-                && sourceFrame->settings().loadsImagesAutomatically()) {
</del><ins>+                && imageElementIsDraggable(downcast<HTMLImageElement>(*element), *sourceFrame)) {
</ins><span class="cx">                 state.type = static_cast<DragSourceAction>(state.type | DragSourceActionImage);
</span><span class="cx">                 return element;
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceWebCorepageiosEventHandlerIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/ios/EventHandlerIOS.mm (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/ios/EventHandlerIOS.mm 2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebCore/page/ios/EventHandlerIOS.mm    2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -572,19 +572,30 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool EventHandler::tryToBeginDataInteractionAtPoint(const IntPoint& clientPosition, const IntPoint& globalPosition)
</del><ins>+bool EventHandler::tryToBeginDataInteractionAtPoint(const IntPoint& clientPosition, const IntPoint&)
</ins><span class="cx"> {
</span><span class="cx">     Ref<Frame> protectedFrame(m_frame);
</span><span class="cx"> 
</span><del>-    PlatformMouseEvent syntheticMousePressEvent(clientPosition, globalPosition, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime(), 0, NoTap);
-    PlatformMouseEvent syntheticMouseMoveEvent(clientPosition, globalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime(), 0, NoTap);
</del><ins>+    auto* document = m_frame.document();
+    if (!document)
+        return false;
</ins><span class="cx"> 
</span><ins>+    document->updateLayoutIgnorePendingStylesheets();
+
+    FloatPoint adjustedClientPositionAsFloatPoint(clientPosition);
+    protectedFrame->nodeRespondingToClickEvents(clientPosition, adjustedClientPositionAsFloatPoint);
+    IntPoint adjustedClientPosition = roundedIntPoint(adjustedClientPositionAsFloatPoint);
+    IntPoint adjustedGlobalPosition = protectedFrame->view()->windowToContents(adjustedClientPosition);
+
+    PlatformMouseEvent syntheticMousePressEvent(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime(), 0, NoTap);
+    PlatformMouseEvent syntheticMouseMoveEvent(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime(), 0, NoTap);
+
</ins><span class="cx">     HitTestRequest request(HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent);
</span><span class="cx">     auto documentPoint = protectedFrame->view() ? protectedFrame->view()->windowToContents(syntheticMouseMoveEvent.position()) : syntheticMouseMoveEvent.position();
</span><del>-    auto hitTestedMouseEvent = m_frame.document()->prepareMouseEvent(request, documentPoint, syntheticMouseMoveEvent);
</del><ins>+    auto hitTestedMouseEvent = document->prepareMouseEvent(request, documentPoint, syntheticMouseMoveEvent);
</ins><span class="cx"> 
</span><span class="cx">     RefPtr<Frame> subframe = subframeForHitTestResult(hitTestedMouseEvent);
</span><del>-    if (subframe && subframe->eventHandler().tryToBeginDataInteractionAtPoint(clientPosition, globalPosition))
</del><ins>+    if (subframe && subframe->eventHandler().tryToBeginDataInteractionAtPoint(adjustedClientPosition, adjustedGlobalPosition))
</ins><span class="cx">         return true;
</span><span class="cx"> 
</span><span class="cx">     // FIXME: This needs to be refactored, along with handleMousePressEvent and handleMouseMoveEvent, so that state associated only with dragging
</span><span class="lines">@@ -597,7 +608,6 @@
</span><span class="cx">     dragState().source = nullptr;
</span><span class="cx">     dragState().draggedContentRange = nullptr;
</span><span class="cx">     m_mouseDownPos = protectedFrame->view()->windowToContents(syntheticMouseMoveEvent.position());
</span><del>-    protectedFrame->document()->updateStyleIfNeeded();
</del><span class="cx"> 
</span><span class="cx">     return handleMouseDraggedEvent(hitTestedMouseEvent, DontCheckDragHysteresis);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/ChangeLog (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/ChangeLog        2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit/mac/ChangeLog   2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -1,5 +1,26 @@
</span><span class="cx"> 2017-06-27  Wenson Hsieh  <wenson_hsieh@apple.com>
</span><span class="cx"> 
</span><ins>+        [iOS DnD] Support dragging out of contenteditable areas without a prior selection
+        https://bugs.webkit.org/show_bug.cgi?id=173854
+        <rdar://problem/32236827>
+
+        Reviewed by Ryosuke Niwa and Tim Horton.
+
+        Vends some information from the DragItem passed into -[WebView _startDrag:] through the WebView as SPI for
+        WebKit1 clients. No behavior change with these changes alone -- see <rdar://problem/32991062> for more detail.
+
+        * WebView/WebView.mm:
+        (-[WebView _startDrag:]):
+        (-[WebView _dragSourceAction]):
+        (-[WebView _draggedLinkTitle]):
+        (-[WebView _draggedLinkURL]):
+        (-[WebView _draggedElementBounds]):
+        (-[WebView _endedDataInteraction:global:]):
+        * WebView/WebViewData.h:
+        * WebView/WebViewPrivate.h:
+
+2017-06-26  Wenson Hsieh  <wenson_hsieh@apple.com>
+
</ins><span class="cx">         Refactor drag start codepaths to plumb a DragItem to client layers
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=173832
</span><span class="cx">         Work towards <rdar://problem/32236827>
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebView.mm (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebView.mm       2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit/mac/WebView/WebView.mm  2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -1840,6 +1840,10 @@
</span><span class="cx">         _private->textIndicatorData = adoptNS([[WebUITextIndicatorData alloc] initWithImage:image textIndicatorData:indicatorData.value() scale:_private->page->deviceScaleFactor()]);
</span><span class="cx">     else
</span><span class="cx">         _private->textIndicatorData = adoptNS([[WebUITextIndicatorData alloc] initWithImage:image scale:_private->page->deviceScaleFactor()]);
</span><ins>+    _private->draggedLinkURL = dragItem.url.isEmpty() ? nil : (NSURL *)dragItem.url;
+    _private->draggedLinkTitle = dragItem.title.isEmpty() ? nil : (NSString *)dragItem.title;
+    _private->draggedElementBounds = dragItem.elementBounds;
+    _private->dragSourceAction = static_cast<WebDragSourceAction>(dragItem.sourceAction);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (CGRect)_dataInteractionCaretRect
</span><span class="lines">@@ -1855,6 +1859,26 @@
</span><span class="cx">     return _private->dataOperationTextIndicator.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (WebDragSourceAction)_dragSourceAction
+{
+    return _private->dragSourceAction;
+}
+
+- (NSString *)_draggedLinkTitle
+{
+    return _private->draggedLinkTitle.get();
+}
+
+- (NSURL *)_draggedLinkURL
+{
+    return _private->draggedLinkURL.get();
+}
+
+- (CGRect)_draggedElementBounds
+{
+    return _private->draggedElementBounds;
+}
+
</ins><span class="cx"> - (WebUITextIndicatorData *)_getDataInteractionData
</span><span class="cx"> {
</span><span class="cx">     return _private->textIndicatorData.get();
</span><span class="lines">@@ -1908,6 +1932,10 @@
</span><span class="cx">     WebThreadLock();
</span><span class="cx">     _private->page->dragController().dragEnded();
</span><span class="cx">     _private->dataOperationTextIndicator = nullptr;
</span><ins>+    _private->draggedElementBounds = CGRectNull;
+    _private->dragSourceAction = WebDragSourceActionNone;
+    _private->draggedLinkTitle = nil;
+    _private->draggedLinkURL = nil;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)_didConcludeEditDataInteraction
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebViewDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebViewData.h (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebViewData.h    2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit/mac/WebView/WebViewData.h       2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #import "WebTypesInternal.h"
</span><span class="cx"> #import "WebDelegateImplementationCaching.h"
</span><ins>+#import "WebUIDelegate.h"
</ins><span class="cx"> #if HAVE(TOUCH_BAR)
</span><span class="cx"> #import <WebCore/AVKitSPI.h>
</span><span class="cx"> #endif
</span><span class="lines">@@ -300,6 +301,10 @@
</span><span class="cx"> #if ENABLE(DATA_INTERACTION)
</span><span class="cx">     RetainPtr<WebUITextIndicatorData> textIndicatorData;
</span><span class="cx">     RetainPtr<WebUITextIndicatorData> dataOperationTextIndicator;
</span><ins>+    CGRect draggedElementBounds;
+    WebDragSourceAction dragSourceAction;
+    RetainPtr<NSURL> draggedLinkURL;
+    RetainPtr<NSString> draggedLinkTitle;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKitmacWebViewWebViewPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/mac/WebView/WebViewPrivate.h (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/mac/WebView/WebViewPrivate.h 2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit/mac/WebView/WebViewPrivate.h    2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -473,6 +473,10 @@
</span><span class="cx"> - (BOOL)_requestStartDataInteraction:(CGPoint)clientPosition globalPosition:(CGPoint)globalPosition;
</span><span class="cx"> - (WebUITextIndicatorData *)_getDataInteractionData;
</span><span class="cx"> @property (nonatomic, readonly, strong, getter=_dataOperationTextIndicator) WebUITextIndicatorData *dataOperationTextIndicator;
</span><ins>+@property (nonatomic, readonly) NSUInteger _dragSourceAction;
+@property (nonatomic, strong, readonly) NSString *_draggedLinkTitle;
+@property (nonatomic, strong, readonly) NSURL *_draggedLinkURL;
+@property (nonatomic, readonly) CGRect _draggedElementBounds;
</ins><span class="cx"> - (uint64_t)_enteredDataInteraction:(id <UIDropSession>)session client:(CGPoint)clientPosition global:(CGPoint)globalPosition operation:(uint64_t)operation;
</span><span class="cx"> - (uint64_t)_updatedDataInteraction:(id <UIDropSession>)session client:(CGPoint)clientPosition global:(CGPoint)globalPosition operation:(uint64_t)operation;
</span><span class="cx"> - (void)_exitedDataInteraction:(id <UIDropSession>)session client:(CGPoint)clientPosition global:(CGPoint)globalPosition operation:(uint64_t)operation;
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog   2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit2/ChangeLog      2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2017-06-27  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS DnD] Support dragging out of contenteditable areas without a prior selection
+        https://bugs.webkit.org/show_bug.cgi?id=173854
+        <rdar://problem/32236827>
+
+        Reviewed by Ryosuke Niwa and Tim Horton.
+
+        Instead of allowing a drag to occur only if a position information request discovers a clickable node, remove
+        the position information request entirely and just call into WebCore to try and begin the drag. Currently, the
+        position information request serves two purposes:
+        1. To adjust the hit-test location to account for nearby clickable nodes.
+        2. To obtain information about the content being dragged.
+
+        The first requirement is fulfilled by performing the drag location adjustment in WebCore instead (see
+        ChangeLogs for more detail). The second requirement is fulfilled by refactoring in
+        https://bugs.webkit.org/show_bug.cgi?id=173832 to fold all information relevant to starting a drag into the
+        DragItem struct, and then propagating the DragItem struct. The relevant information from the position
+        information update is now populated when the UI process receives the drag start response.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView _startDrag:item:]):
+        (-[WKContentView computeClientAndGlobalPointsForDropSession:outClientPoint:outGlobalPoint:]):
+        (-[WKContentView _dragInteraction:prepareForSession:completion:]):
+        (-[WKContentView _api_dropInteraction:sessionDidEnter:]):
+        (-[WKContentView _api_dropInteraction:sessionDidUpdate:]):
+        (positionInformationMayStartDataInteraction): Deleted.
+
</ins><span class="cx"> 2017-06-27  Chris Dumez  <cdumez@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [iOS] Avoid taking / releasing process assertions too quickly due to database activity
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm   2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm      2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -4228,6 +4228,10 @@
</span><span class="cx">     _dataInteractionState.image = adoptNS([[UIImage alloc] initWithCGImage:image.get() scale:_page->deviceScaleFactor() orientation:UIImageOrientationUp]);
</span><span class="cx">     _dataInteractionState.indicatorData = item.image.indicatorData();
</span><span class="cx">     _dataInteractionState.sourceAction = static_cast<DragSourceAction>(item.sourceAction);
</span><ins>+    _dataInteractionState.adjustedOrigin = item.eventPositionInContentCoordinates;
+    _dataInteractionState.elementBounds = item.elementBounds;
+    _dataInteractionState.linkTitle = item.title.isEmpty() ? nil : (NSString *)item.title;
+    _dataInteractionState.linkURL = item.url.isEmpty() ? nil : (NSURL *)item.url;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)_didHandleStartDataInteractionRequest:(BOOL)started
</span><span class="lines">@@ -4500,11 +4504,6 @@
</span><span class="cx">     return WKDragDestinationActionAny & ~WKDragDestinationActionLoad;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static BOOL positionInformationMayStartDataInteraction(const InteractionInformationAtPosition& positionInformation)
-{
-    return positionInformation.isImage || positionInformation.isLink || positionInformation.isAttachment || positionInformation.hasSelectionAtPosition;
-}
-
</del><span class="cx"> - (id <UIDragDropSession>)currentDragOrDropSession
</span><span class="cx"> {
</span><span class="cx">     if (_dataInteractionState.dropSession)
</span><span class="lines">@@ -4528,28 +4527,12 @@
</span><span class="cx"> 
</span><span class="cx">     [self cleanUpDragSourceSessionState];
</span><span class="cx"> 
</span><del>-    CGPoint dragOrigin = [session locationInView:self];
-    RetainPtr<WKContentView> retainedSelf(self);
</del><ins>+    auto dragOrigin = roundedIntPoint([session locationInView:self]);
+    _dataInteractionState.dragStartCompletionBlock = completion;
+    _dataInteractionState.dragSession = session;
+    _page->requestStartDataInteraction(dragOrigin, roundedIntPoint([self convertPoint:dragOrigin toView:self.window]));
</ins><span class="cx"> 
</span><del>-    [self doAfterPositionInformationUpdate:[retainedSelf, session, dragOrigin, capturedBlock = makeBlockPtr(completion)] (InteractionInformationAtPosition positionInformation) {
-        if (!positionInformationMayStartDataInteraction(positionInformation)) {
-            RELEASE_LOG(DragAndDrop, "Drag session failed: %p (no draggable content at {%.1f, %.1f})", session, dragOrigin.x, dragOrigin.y);
-            capturedBlock();
-            return;
-        }
-
-        auto& state = retainedSelf->_dataInteractionState;
-        state.dragStartCompletionBlock = capturedBlock;
-        state.adjustedOrigin = retainedSelf->_positionInformation.adjustedPointForNodeRespondingToClickEvents;
-        state.elementBounds = retainedSelf->_positionInformation.bounds;
-        state.linkTitle = retainedSelf->_positionInformation.title;
-        state.linkURL = retainedSelf->_positionInformation.url;
-        state.dragSession = session;
-        retainedSelf->_page->requestStartDataInteraction(roundedIntPoint(state.adjustedOrigin), roundedIntPoint([retainedSelf convertPoint:state.adjustedOrigin toView:[retainedSelf window]]));
-
-        auto elementBounds = state.elementBounds;
-        RELEASE_LOG(DragAndDrop, "Drag session requested: %p at element bounds: {{%.1f, %.1f}, {%.1f, %.1f}}", session, elementBounds.origin.x, elementBounds.origin.y, elementBounds.size.width, elementBounds.size.height);
-    } forRequest:InteractionInformationRequest(roundedIntPoint(dragOrigin))];
</del><ins>+    RELEASE_LOG(DragAndDrop, "Drag session requested: %p at origin: {%d, %d}", session, dragOrigin.x(), dragOrigin.y());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id <UIDragSession>)session
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Tools/ChangeLog       2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2017-06-27  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS DnD] Support dragging out of contenteditable areas without a prior selection
+        https://bugs.webkit.org/show_bug.cgi?id=173854
+        <rdar://problem/32236827>
+
+        Reviewed by Ryosuke Niwa and Tim Horton.
+
+        Adds a new test to check that an image can be dragged out of a contenteditable and dropped.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html: Added.
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
</ins><span class="cx"> 2017-06-27  Don Olmstead  <don.olmstead@sony.com>
</span><span class="cx"> 
</span><span class="cx">         [PAL] Add symbol export macros for PAL
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj   2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -642,6 +642,7 @@
</span><span class="cx">          F4538EF71E8473E600B5C953 /* large-red-square.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4538EF01E846B4100B5C953 /* large-red-square.png */; };
</span><span class="cx">          F46849BE1EEF58E400B937FE /* UIPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */; };
</span><span class="cx">          F46849C01EEF5EF300B937FE /* rich-and-plain-text.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46849BF1EEF5EDC00B937FE /* rich-and-plain-text.html */; };
</span><ins>+               F469FB241F01804B00401539 /* contenteditable-and-target.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F469FB231F01803500401539 /* contenteditable-and-target.html */; };
</ins><span class="cx">           F46A095A1ED8A6E600D4AA55 /* apple.gif in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30EB1ED28619000482E1 /* apple.gif */; };
</span><span class="cx">          F46A095B1ED8A6E600D4AA55 /* gif-and-file-input.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */; };
</span><span class="cx">          F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; };
</span><span class="lines">@@ -727,6 +728,7 @@
</span><span class="cx">                  dstPath = TestWebKitAPI.resources;
</span><span class="cx">                  dstSubfolderSpec = 7;
</span><span class="cx">                  files = (
</span><ins>+                               F469FB241F01804B00401539 /* contenteditable-and-target.html in Copy Resources */,
</ins><span class="cx">                           F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */,
</span><span class="cx">                          F41AB99F1EF4696B0083FA08 /* autofocus-contenteditable.html in Copy Resources */,
</span><span class="cx">                          F41AB9A01EF4696B0083FA08 /* background-image-link-and-input.html in Copy Resources */,
</span><span class="lines">@@ -1609,6 +1611,7 @@
</span><span class="cx">          F4538EF01E846B4100B5C953 /* large-red-square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "large-red-square.png"; sourceTree = "<group>"; };
</span><span class="cx">          F46849BD1EEF58E400B937FE /* UIPasteboardTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UIPasteboardTests.mm; sourceTree = "<group>"; };
</span><span class="cx">          F46849BF1EEF5EDC00B937FE /* rich-and-plain-text.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "rich-and-plain-text.html"; sourceTree = "<group>"; };
</span><ins>+               F469FB231F01803500401539 /* contenteditable-and-target.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-and-target.html"; sourceTree = "<group>"; };
</ins><span class="cx">           F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; };
</span><span class="cx">          F47D30EB1ED28619000482E1 /* apple.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = apple.gif; sourceTree = "<group>"; };
</span><span class="cx">          F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
</span><span class="lines">@@ -2008,6 +2011,7 @@
</span><span class="cx">                          F4B825D61EF4DBD4006E417F /* compressed-files.zip */,
</span><span class="cx">                          F41AB9981EF4692C0083FA08 /* autofocus-contenteditable.html */,
</span><span class="cx">                          F41AB9971EF4692C0083FA08 /* background-image-link-and-input.html */,
</span><ins>+                               F469FB231F01803500401539 /* contenteditable-and-target.html */,
</ins><span class="cx">                           F41AB99C1EF4692C0083FA08 /* contenteditable-and-textarea.html */,
</span><span class="cx">                          F41AB99E1EF4692C0083FA08 /* div-and-large-image.html */,
</span><span class="cx">                          F41AB99B1EF4692C0083FA08 /* file-uploading.html */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWebKit2Cocoacontenteditableandtargethtml"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html (0 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html                             (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/contenteditable-and-target.html        2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -0,0 +1,44 @@
</span><ins>+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+        <style>
+        body {
+            width: 100%;
+            height: 100%;
+            margin: 0;
+        }
+
+        img {
+            height: 200px;
+        }
+
+        #source, #target {
+            width: 100%;
+            height: 200px;
+            font-size: 150px;
+            white-space: nowrap;
+            box-sizing: border-box;
+        }
+
+        #target {
+            border: green 1px dashed;
+            color: green;
+            border-width: 5px;
+        }
+        </style>
+</head>
+
+<body>
+    <div contenteditable id="source"><img src="icon.png"></img></div>
+    <code><div id="target"></div></code>
+    <script>
+    target.addEventListener("dragenter", event => event.preventDefault());
+    target.addEventListener("dragover", event => event.preventDefault());
+    target.addEventListener("drop", event => {
+        target.textContent = "PASS";
+        event.preventDefault();
+    });
+    </script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsiosDataInteractionTestsmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (218854 => 218855)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm      2017-06-27 23:55:27 UTC (rev 218854)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm 2017-06-28 00:36:31 UTC (rev 218855)
</span><span class="lines">@@ -274,6 +274,17 @@
</span><span class="cx">     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [dataInteractionSimulator finalSelectionRects]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST(DataInteractionTests, DragImageFromContentEditable)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+    [webView synchronouslyLoadTestPageNamed:@"contenteditable-and-target"];
+    [dataInteractionSimulator runFrom:CGPointMake(100, 100) to:CGPointMake(100, 300)];
+
+    EXPECT_WK_STREQ("PASS", [webView stringByEvaluatingJavaScript:@"target.textContent"]);
+}
+
</ins><span class="cx"> TEST(DataInteractionTests, TextAreaToInput)
</span><span class="cx"> {
</span><span class="cx">     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
</span></span></pre>
</div>
</div>

</body>
</html>