Title: [221900] trunk
Revision
221900
Author
wenson_hs...@apple.com
Date
2017-09-11 19:09:28 -0700 (Mon, 11 Sep 2017)

Log Message

[iOS WK2] Support tapping to add items to the current drag session in web content
https://bugs.webkit.org/show_bug.cgi?id=176421
<rdar://problem/31144674>

Reviewed by Tim Horton.

Source/WebCore:

Refactors some drag initiation logic to handle starting a drag when data has already been written to the
pasteboard (in the case of iOS, WebItemProviderPasteboard). See annotated comments below for more detail.

Tests: DataInteractionTests.AdditionalLinkAndImageIntoContentEditable

* page/DragActions.h:
* page/DragController.cpp:
(WebCore::DragController::startDrag):

Add a HasNonDefaultPasteboardData argument here, and replace checks for !dataTransfer.pasteboard().hasData()
with checks for whether the argument is HasNonDefaultPasteboardData::No. These checks for Pasteboard::hasData()
currently prevent us from overwriting custom pasteboard data, in the case that the page has written pasteboard
data using the event's DataTransfer. However, in the case of adding additional drag items to the session, we
will already have pasteboard data, so these checks will prevent us from writing default data to the pasteboard.
See EventHandler::handleDrag for more detail.

* page/DragController.h:
* page/DragState.h:

Remove the draggedContentRange member from DragState. See below.

* page/EventHandler.cpp:
(WebCore::removeDraggedContentDocumentMarkersFromAllFramesInPage):

Simplify the handling of dragged content range markers. Instead of storing the DOM Range being dragged and
removing/repainting the range after dragging ends, just repaint the contentRenderer of the frame being dragged.
When the dragging session has completely ended, remove all dragged content ranges from the page's mainframe and
all of its subframes, and repaint everything.

(WebCore::EventHandler::dragCancelled):
(WebCore::EventHandler::didStartDrag):
(WebCore::EventHandler::dragSourceEndedAt):

Add a MayExtendDragSession argument, indicating whether or not the web process will attempt to continue the drag
session, in which case EventHandler::dragSourceEndedAt should not remove any existing dragged content range
document markers.

(WebCore::EventHandler::dispatchDragStartEvent):

Helper method to dispatch a `dragstart` event, return whether or not to proceed with the drag, and also compute
(as an outparam) whether or not custom pasteboard data was written during the event.

(WebCore::EventHandler::handleDrag):

If custom data was written during `dragstart`, pass along HasNonDefaultPasteboardData::Yes when calling
DragController::startDrag.

(WebCore::repaintContentsOfRange): Deleted.
* page/EventHandler.h:
* page/ios/EventHandlerIOS.mm:
(WebCore::EventHandler::tryToBeginDataInteractionAtPoint):
* platform/Pasteboard.h:
* platform/ios/PasteboardIOS.mm:
(WebCore::Pasteboard::changeCount const):
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard setItemProviders:]):

Stop clearing out the staged item provider registration list when setting item providers. After refactoring in
r221595, staged registration lists are now automatically cleared out when (1) the drag-and-drop interaction
state is cleared out in the UI process, or (2) when the registration list is taken by WKContentView (see
-takeRegistrationList) when generating an item provider.

* platform/mac/PasteboardMac.mm:
(WebCore::Pasteboard::changeCount const):

Add a changeCount method to Pasteboard on Cocoa platforms (Mac, iOS) which support changeCount natively. In
theory, there's no reason Windows, GTK and WPE ports can't also implement a similar mechanism in
PlatformPasteboard, but this isn't needed for anything yet. Upon dragstart, it is safe to assume that the
pasteboard has been cleared on these platforms, so checking for Pasteboard::hasData (as we do for all platforms
currently) is sufficient.

Source/WebKit:

To request additional drag items, end the current drag in the web page and try to begin a drag at the new
location. This process is transparent to the UI process, which still maintains the same UIDragSession with the
old drag source.

As opposed to firing a new event (for instance: `adddragitem`), this approach is taken to ensure that if the
page wants to preventDefault() on `dragstart`, it would also prevent the user from adding it as an additional
drag item. Using the new event approach, dealing with this case would either require the page to listen for a
new event and call preventDefault(), which would break compatibility with pages that only preventDefault() on
`dragstart`, or it would require the default behavior of this new event to be _not_ adding a drag item, in which
case this approach would require pages to adopt the new event in some form.

* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::requestAdditionalItemsForDragSession):

Tools:

Adds a new drag and drop test that begins a drag on a text selection, adds an image and a link, and then drops
into a contenteditable area. This verifies that the text, link and image are inserted into the editable area
upon drop.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (221899 => 221900)


--- trunk/Source/WebCore/ChangeLog	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/ChangeLog	2017-09-12 02:09:28 UTC (rev 221900)
@@ -1,3 +1,82 @@
+2017-09-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS WK2] Support tapping to add items to the current drag session in web content
+        https://bugs.webkit.org/show_bug.cgi?id=176421
+        <rdar://problem/31144674>
+
+        Reviewed by Tim Horton.
+
+        Refactors some drag initiation logic to handle starting a drag when data has already been written to the
+        pasteboard (in the case of iOS, WebItemProviderPasteboard). See annotated comments below for more detail.
+
+        Tests: DataInteractionTests.AdditionalLinkAndImageIntoContentEditable
+
+        * page/DragActions.h:
+        * page/DragController.cpp:
+        (WebCore::DragController::startDrag):
+
+        Add a HasNonDefaultPasteboardData argument here, and replace checks for !dataTransfer.pasteboard().hasData()
+        with checks for whether the argument is HasNonDefaultPasteboardData::No. These checks for Pasteboard::hasData()
+        currently prevent us from overwriting custom pasteboard data, in the case that the page has written pasteboard
+        data using the event's DataTransfer. However, in the case of adding additional drag items to the session, we
+        will already have pasteboard data, so these checks will prevent us from writing default data to the pasteboard.
+        See EventHandler::handleDrag for more detail.
+
+        * page/DragController.h:
+        * page/DragState.h:
+
+        Remove the draggedContentRange member from DragState. See below.
+
+        * page/EventHandler.cpp:
+        (WebCore::removeDraggedContentDocumentMarkersFromAllFramesInPage):
+
+        Simplify the handling of dragged content range markers. Instead of storing the DOM Range being dragged and
+        removing/repainting the range after dragging ends, just repaint the contentRenderer of the frame being dragged.
+        When the dragging session has completely ended, remove all dragged content ranges from the page's mainframe and
+        all of its subframes, and repaint everything.
+
+        (WebCore::EventHandler::dragCancelled):
+        (WebCore::EventHandler::didStartDrag):
+        (WebCore::EventHandler::dragSourceEndedAt):
+
+        Add a MayExtendDragSession argument, indicating whether or not the web process will attempt to continue the drag
+        session, in which case EventHandler::dragSourceEndedAt should not remove any existing dragged content range
+        document markers.
+
+        (WebCore::EventHandler::dispatchDragStartEvent):
+
+        Helper method to dispatch a `dragstart` event, return whether or not to proceed with the drag, and also compute
+        (as an outparam) whether or not custom pasteboard data was written during the event.
+
+        (WebCore::EventHandler::handleDrag):
+
+        If custom data was written during `dragstart`, pass along HasNonDefaultPasteboardData::Yes when calling
+        DragController::startDrag.
+
+        (WebCore::repaintContentsOfRange): Deleted.
+        * page/EventHandler.h:
+        * page/ios/EventHandlerIOS.mm:
+        (WebCore::EventHandler::tryToBeginDataInteractionAtPoint):
+        * platform/Pasteboard.h:
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::changeCount const):
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderPasteboard setItemProviders:]):
+
+        Stop clearing out the staged item provider registration list when setting item providers. After refactoring in
+        r221595, staged registration lists are now automatically cleared out when (1) the drag-and-drop interaction
+        state is cleared out in the UI process, or (2) when the registration list is taken by WKContentView (see
+        -takeRegistrationList) when generating an item provider.
+
+        * platform/mac/PasteboardMac.mm:
+        (WebCore::Pasteboard::changeCount const):
+
+        Add a changeCount method to Pasteboard on Cocoa platforms (Mac, iOS) which support changeCount natively. In
+        theory, there's no reason Windows, GTK and WPE ports can't also implement a similar mechanism in
+        PlatformPasteboard, but this isn't needed for anything yet. Upon dragstart, it is safe to assume that the
+        pasteboard has been cleared on these platforms, so checking for Pasteboard::hasData (as we do for all platforms
+        currently) is sufficient.
+
 2017-09-11  Ryan Haddad  <ryanhad...@apple.com>
 
         Unreviewed, rolling out r221762.

Modified: trunk/Source/WebCore/page/DragActions.h (221899 => 221900)


--- trunk/Source/WebCore/page/DragActions.h	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/DragActions.h	2017-09-12 02:09:28 UTC (rev 221900)
@@ -62,5 +62,8 @@
         DragOperationDelete  = 32,
         DragOperationEvery   = UINT_MAX
     } DragOperation;
+
+    enum class MayExtendDragSession { No, Yes };
+    enum class HasNonDefaultPasteboardData { No, Yes };
     
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/DragController.cpp (221899 => 221900)


--- trunk/Source/WebCore/page/DragController.cpp	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/DragController.cpp	2017-09-12 02:09:28 UTC (rev 221900)
@@ -868,7 +868,7 @@
     return IntPoint(xpos, ypos);
 }
 
-bool DragController::startDrag(Frame& src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin)
+bool DragController::startDrag(Frame& src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, HasNonDefaultPasteboardData hasData)
 {
     if (!src.view() || !src.contentRenderer() || !state.source)
         return false;
@@ -933,7 +933,7 @@
     ASSERT(state.source);
     Element& element = *state.source;
 
-    bool mustUseLegacyDragClient = dataTransfer.pasteboard().hasData() || m_client.useLegacyDragClient();
+    bool mustUseLegacyDragClient = hasData == HasNonDefaultPasteboardData::Yes || m_client.useLegacyDragClient();
 
     IntRect dragImageBounds;
     Image* image = getImage(element);
@@ -940,7 +940,7 @@
     if (state.type == DragSourceActionSelection) {
         PasteboardWriterData pasteboardWriterData;
 
-        if (!dataTransfer.pasteboard().hasData()) {
+        if (hasData == HasNonDefaultPasteboardData::No) {
             if (src.selection().selection().isNone()) {
                 // The page may have cleared out the selection in the dragstart handler, in which case we should bail
                 // out of the drag, since there is no content to write to the pasteboard.
@@ -1016,7 +1016,7 @@
         // We shouldn't be starting a drag for an image that can't provide an extension.
         // This is an early detection for problems encountered later upon drop.
         ASSERT(!image->filenameExtension().isEmpty());
-        if (!dataTransfer.pasteboard().hasData()) {
+        if (hasData == HasNonDefaultPasteboardData::No) {
             m_draggingImageURL = imageURL;
             if (element.isContentRichlyEditable())
                 selectElement(element);
@@ -1040,7 +1040,7 @@
 
         String textContentWithSimplifiedWhiteSpace = hitTestResult.textContent().simplifyWhiteSpace();
 
-        if (!dataTransfer.pasteboard().hasData()) {
+        if (hasData == HasNonDefaultPasteboardData::No) {
             // Simplify whitespace so the title put on the dataTransfer resembles what the user sees
             // on the web page. This includes replacing newlines with spaces.
             if (mustUseLegacyDragClient)
@@ -1103,7 +1103,7 @@
 
         src.editor().setIgnoreSelectionChanges(true);
         auto previousSelection = src.selection().selection();
-        if (!dataTransfer.pasteboard().hasData()) {
+        if (hasData == HasNonDefaultPasteboardData::No) {
             selectElement(element);
             if (!attachmentURL.isEmpty()) {
                 // Use the attachment URL specified by the file attribute to populate the pasteboard.

Modified: trunk/Source/WebCore/page/DragController.h (221899 => 221900)


--- trunk/Source/WebCore/page/DragController.h	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/DragController.h	2017-09-12 02:09:28 UTC (rev 221900)
@@ -91,7 +91,7 @@
         
         WEBCORE_EXPORT void placeDragCaret(const IntPoint&);
         
-        bool startDrag(Frame& src, const DragState&, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin);
+        bool startDrag(Frame& src, const DragState&, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, HasNonDefaultPasteboardData);
         static const IntSize& maxDragImageSize();
         
         static const int MaxOriginalImageArea;

Modified: trunk/Source/WebCore/page/DragState.h (221899 => 221900)


--- trunk/Source/WebCore/page/DragState.h	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/DragState.h	2017-09-12 02:09:28 UTC (rev 221900)
@@ -34,7 +34,6 @@
 
 struct DragState {
     RefPtr<Element> source; // Element that may be a drag source, for the current mouse gesture.
-    RefPtr<Range> draggedContentRange;
     bool shouldDispatchEvents;
     DragSourceAction type;
     RefPtr<DataTransfer> dataTransfer; // Used on only the source side of dragging.

Modified: trunk/Source/WebCore/page/EventHandler.cpp (221899 => 221900)


--- trunk/Source/WebCore/page/EventHandler.cpp	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2017-09-12 02:09:28 UTC (rev 221900)
@@ -66,6 +66,7 @@
 #include "MouseEventWithHitTestResults.h"
 #include "Page.h"
 #include "PageOverlayController.h"
+#include "Pasteboard.h"
 #include "PlatformEvent.h"
 #include "PlatformKeyboardEvent.h"
 #include "PlatformWheelEvent.h"
@@ -3465,31 +3466,22 @@
     dragState().dataTransfer = nullptr;
 }
 
-static void repaintContentsOfRange(RefPtr<Range> range)
+static void removeDraggedContentDocumentMarkersFromAllFramesInPage(Page& page)
 {
-    if (!range)
-        return;
+    for (Frame* frame = &page.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        if (auto* document = frame->document())
+            document->markers().removeMarkers(DocumentMarker::DraggedContent);
+    }
 
-    auto* container = range->commonAncestorContainer();
-    if (!container)
-        return;
-
-    // This ensures that all nodes enclosed in this Range are repainted.
-    if (auto rendererToRepaint = container->renderer()) {
-        if (auto* containingRenderer = rendererToRepaint->container())
-            rendererToRepaint = containingRenderer;
-        rendererToRepaint->repaint();
-    }
+    if (auto* mainFrameRenderer = page.mainFrame().contentRenderer())
+        mainFrameRenderer->repaintRootContents();
 }
 
 void EventHandler::dragCancelled()
 {
 #if ENABLE(DATA_INTERACTION)
-    if (auto range = dragState().draggedContentRange) {
-        range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent);
-        repaintContentsOfRange(range);
-    }
-    dragState().draggedContentRange = nullptr;
+    if (auto* page = m_frame.page())
+        removeDraggedContentDocumentMarkersFromAllFramesInPage(*page);
 #endif
 }
 
@@ -3504,22 +3496,24 @@
     if (!renderer)
         return;
 
+    RefPtr<Range> draggedContentRange;
     if (dragState().type & DragSourceActionSelection)
-        dragState().draggedContentRange = m_frame.selection().selection().toNormalizedRange();
+        draggedContentRange = m_frame.selection().selection().toNormalizedRange();
     else {
         Position startPosition(dragSource.get(), Position::PositionIsBeforeAnchor);
         Position endPosition(dragSource.get(), Position::PositionIsAfterAnchor);
-        dragState().draggedContentRange = Range::create(dragSource->document(), startPosition, endPosition);
+        draggedContentRange = Range::create(dragSource->document(), startPosition, endPosition);
     }
 
-    if (auto range = dragState().draggedContentRange) {
-        range->ownerDocument().markers().addDraggedContentMarker(range.get());
-        repaintContentsOfRange(range);
+    if (draggedContentRange) {
+        draggedContentRange->ownerDocument().markers().addDraggedContentMarker(draggedContentRange.get());
+        if (auto* renderer = m_frame.contentRenderer())
+            renderer->repaintRootContents();
     }
 #endif
 }
 
-void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
+void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation, MayExtendDragSession mayExtendDragSession)
 {
     // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
     HitTestRequest request(HitTestRequest::Release | HitTestRequest::DisallowUserAgentShadowContent);
@@ -3532,9 +3526,9 @@
     }
     invalidateDataTransfer();
 
-    if (auto range = dragState().draggedContentRange) {
-        range->ownerDocument().markers().removeMarkers(DocumentMarker::DraggedContent);
-        repaintContentsOfRange(range);
+    if (mayExtendDragSession == MayExtendDragSession::No) {
+        if (auto* page = m_frame.page())
+            removeDraggedContentDocumentMarkersFromAllFramesInPage(*page);
     }
 
     dragState().source = nullptr;
@@ -3555,6 +3549,23 @@
 {
     return !dispatchDragEvent(eventType, *dragState().source, event, dragState().dataTransfer.get());
 }
+
+bool EventHandler::dispatchDragStartEvent(HasNonDefaultPasteboardData& hasNonDefaultPasteboardData)
+{
+#if PLATFORM(COCOA)
+    auto changeCountBeforeDragStart = dragState().dataTransfer->pasteboard().changeCount();
+#endif
+
+    bool mayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown);
+
+#if PLATFORM(COCOA)
+    hasNonDefaultPasteboardData = changeCountBeforeDragStart != dragState().dataTransfer->pasteboard().changeCount() ? HasNonDefaultPasteboardData::Yes : HasNonDefaultPasteboardData::No;
+#else
+    hasNonDefaultPasteboardData = dragState().dataTransfer->pasteboard().hasData() ? HasNonDefaultPasteboardData::Yes : HasNonDefaultPasteboardData::No;
+#endif
+
+    return mayStartDrag && !m_frame.selection().selection().isInPasswordField();
+}
     
 static bool ExactlyOneBitSet(DragSourceAction n)
 {
@@ -3660,6 +3671,7 @@
     invalidateDataTransfer();
 
     dragState().dataTransfer = createDraggingDataTransfer();
+    HasNonDefaultPasteboardData hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No;
     
     if (dragState().shouldDispatchEvents) {
         // Check to see if the is a DOM based drag. If it is, get the DOM specified drag image and offset.
@@ -3680,8 +3692,7 @@
             }
         } 
 
-        m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
-            && !m_frame.selection().selection().isInPasswordField();
+        m_mouseDownMayStartDrag = dispatchDragStartEvent(hasNonDefaultPasteboardData);
 
         dragState().dataTransfer->makeInvalidForSecurity();
 
@@ -3698,7 +3709,7 @@
     
     if (m_mouseDownMayStartDrag) {
         Page* page = m_frame.page();
-        m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos);
+        m_didStartDrag = page && page->dragController().startDrag(m_frame, dragState(), srcOp, event.event(), m_mouseDownPos, hasNonDefaultPasteboardData);
         // In WebKit2 we could re-enter this code and start another drag.
         // On OS X this causes problems with the ownership of the pasteboard and the promised types.
         if (m_didStartDrag) {

Modified: trunk/Source/WebCore/page/EventHandler.h (221899 => 221900)


--- trunk/Source/WebCore/page/EventHandler.h	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/EventHandler.h	2017-09-12 02:09:28 UTC (rev 221900)
@@ -256,7 +256,7 @@
     
     WEBCORE_EXPORT void didStartDrag();
     WEBCORE_EXPORT void dragCancelled();
-    WEBCORE_EXPORT void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
+    WEBCORE_EXPORT void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation, MayExtendDragSession = MayExtendDragSession::No);
 #endif
 
     void focusDocumentView();
@@ -405,6 +405,7 @@
     void clearDragState();
 
     bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
+    bool dispatchDragStartEvent(HasNonDefaultPasteboardData&);
 
     bool dragHysteresisExceeded(const FloatPoint&) const;
     bool dragHysteresisExceeded(const IntPoint&) const;

Modified: trunk/Source/WebCore/page/ios/EventHandlerIOS.mm (221899 => 221900)


--- trunk/Source/WebCore/page/ios/EventHandlerIOS.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/page/ios/EventHandlerIOS.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -606,7 +606,6 @@
 
     SetForScope<bool> mousePressed(m_mousePressed, true);
     dragState().source = nullptr;
-    dragState().draggedContentRange = nullptr;
     m_mouseDownPos = protectedFrame->view()->windowToContents(syntheticMouseMoveEvent.position());
 
     return handleMouseDraggedEvent(hitTestedMouseEvent, DontCheckDragHysteresis);

Modified: trunk/Source/WebCore/platform/Pasteboard.h (221899 => 221900)


--- trunk/Source/WebCore/platform/Pasteboard.h	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/platform/Pasteboard.h	2017-09-12 02:09:28 UTC (rev 221900)
@@ -219,6 +219,7 @@
 
     WEBCORE_EXPORT static NSArray *supportedFileUploadPasteboardTypes();
     const String& name() const { return m_pasteboardName; }
+    long changeCount() const;
 #endif
 
 #if PLATFORM(WIN)

Modified: trunk/Source/WebCore/platform/ios/PasteboardIOS.mm (221899 => 221900)


--- trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/platform/ios/PasteboardIOS.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -299,6 +299,11 @@
     }
 }
 
+long Pasteboard::changeCount() const
+{
+    return platformStrategies()->pasteboardStrategy()->changeCount(m_pasteboardName);
+}
+
 NSArray *Pasteboard::supportedWebContentPasteboardTypes()
 {
     return @[(id)WebArchivePboardType, (id)kUTTypeFlatRTFD, (id)kUTTypeRTF, (id)kUTTypeHTML, (id)kUTTypePNG, (id)kUTTypeTIFF, (id)kUTTypeJPEG, (id)kUTTypeGIF, (id)kUTTypeURL, (id)kUTTypeText];

Modified: trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm (221899 => 221900)


--- trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -277,7 +277,6 @@
     _itemProviders = itemProviders;
     _changeCount++;
     _cachedTypeIdentifiers = nil;
-    _stagedRegistrationInfoList = nil;
 
     NSMutableArray *typeToFileURLMaps = [NSMutableArray arrayWithCapacity:itemProviders.count];
     [itemProviders enumerateObjectsUsingBlock:[typeToFileURLMaps] (UIItemProvider *, NSUInteger, BOOL *) {

Modified: trunk/Source/WebCore/platform/mac/PasteboardMac.mm (221899 => 221900)


--- trunk/Source/WebCore/platform/mac/PasteboardMac.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebCore/platform/mac/PasteboardMac.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -107,6 +107,11 @@
     return types;
 }
 
+long Pasteboard::changeCount() const
+{
+    return platformStrategies()->pasteboardStrategy()->changeCount(m_pasteboardName);
+}
+
 NSArray *Pasteboard::supportedFileUploadPasteboardTypes()
 {
     return @[ (NSString *)NSFilesPromisePboardType, (NSString *)NSFilenamesPboardType ];

Modified: trunk/Source/WebKit/ChangeLog (221899 => 221900)


--- trunk/Source/WebKit/ChangeLog	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebKit/ChangeLog	2017-09-12 02:09:28 UTC (rev 221900)
@@ -1,3 +1,25 @@
+2017-09-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS WK2] Support tapping to add items to the current drag session in web content
+        https://bugs.webkit.org/show_bug.cgi?id=176421
+        <rdar://problem/31144674>
+
+        Reviewed by Tim Horton.
+
+        To request additional drag items, end the current drag in the web page and try to begin a drag at the new
+        location. This process is transparent to the UI process, which still maintains the same UIDragSession with the
+        old drag source.
+
+        As opposed to firing a new event (for instance: `adddragitem`), this approach is taken to ensure that if the
+        page wants to preventDefault() on `dragstart`, it would also prevent the user from adding it as an additional
+        drag item. Using the new event approach, dealing with this case would either require the page to listen for a
+        new event and call preventDefault(), which would break compatibility with pages that only preventDefault() on
+        `dragstart`, or it would require the default behavior of this new event to be _not_ adding a drag item, in which
+        case this approach would require pages to adopt the new event in some form.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::requestAdditionalItemsForDragSession):
+
 2017-09-11  Alex Christensen  <achristen...@webkit.org>
 
         Clean up API::UIClient

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (221899 => 221900)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -57,6 +57,7 @@
 #import <WebCore/DataDetection.h>
 #import <WebCore/DiagnosticLoggingClient.h>
 #import <WebCore/DiagnosticLoggingKeys.h>
+#import <WebCore/DragController.h>
 #import <WebCore/Editing.h>
 #import <WebCore/Editor.h>
 #import <WebCore/Element.h>
@@ -633,9 +634,15 @@
 
 void WebPage::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition)
 {
-    notImplemented();
+    // To augment the platform drag session with additional items, end the current drag session and begin a new drag session with the new drag item.
+    // This process is opaque to the UI process, which still maintains the old drag item in its drag session. Similarly, this persistent drag session
+    // is opaque to the web process, which only sees that the current drag has ended, and that a new one is beginning.
+    PlatformMouseEvent event(clientPosition, globalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime(), 0, NoTap);
+    m_page->dragController().dragEnded();
+    m_page->mainFrame().eventHandler().dragSourceEndedAt(event, DragOperationNone, MayExtendDragSession::Yes);
 
-    send(Messages::WebPageProxy::DidHandleAdditionalDragItemsRequest(false));
+    bool didHandleDrag = m_page->mainFrame().eventHandler().tryToBeginDataInteractionAtPoint(clientPosition, globalPosition);
+    send(Messages::WebPageProxy::DidHandleAdditionalDragItemsRequest(didHandleDrag));
 }
 
 void WebPage::didConcludeEditDataInteraction()

Modified: trunk/Tools/ChangeLog (221899 => 221900)


--- trunk/Tools/ChangeLog	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Tools/ChangeLog	2017-09-12 02:09:28 UTC (rev 221900)
@@ -1,3 +1,18 @@
+2017-09-11  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS WK2] Support tapping to add items to the current drag session in web content
+        https://bugs.webkit.org/show_bug.cgi?id=176421
+        <rdar://problem/31144674>
+
+        Reviewed by Tim Horton.
+
+        Adds a new drag and drop test that begins a drag on a text selection, adds an image and a link, and then drops
+        into a contenteditable area. This verifies that the text, link and image are inserted into the editable area
+        upon drop.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
 2017-09-11  Lucas Forschler  <lforsch...@apple.com>
 
         bisect-builds: add --list option

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (221899 => 221900)


--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-09-12 02:05:21 UTC (rev 221899)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm	2017-09-12 02:09:28 UTC (rev 221900)
@@ -1394,6 +1394,21 @@
     EXPECT_WK_STREQ("ABCD", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
 }
 
+TEST(DataInteractionTests, AdditionalLinkAndImageIntoContentEditable)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"selected-text-image-link-and-editable"];
+
+    auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [simulator runFrom:CGPointMake(50, 50) to:CGPointMake(50, 400) additionalItemRequestLocations:@{
+        @0.33: [NSValue valueWithCGPoint:CGPointMake(50, 150)],
+        @0.66: [NSValue valueWithCGPoint:CGPointMake(50, 250)]
+    }];
+    EXPECT_WK_STREQ("ABCD A link", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
+    EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!!editor.querySelector('img')"]);
+    EXPECT_WK_STREQ("https://www.apple.com/", [webView stringByEvaluatingJavaScript:@"editor.querySelector('a').href"]);
+}
+
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(DATA_INTERACTION)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to