Title: [245778] trunk
Revision
245778
Author
[email protected]
Date
2019-05-26 04:31:49 -0700 (Sun, 26 May 2019)

Log Message

[iOS] Dropped text, attachments, and images should animate into place
https://bugs.webkit.org/show_bug.cgi?id=198243
<rdar://problem/35205373>

Reviewed by Tim Horton.

Source/WebCore:

Add some hooks to notify the chrome client when an HTMLImageElement's image is finished loading. See WebKit
changelog for more detail.

Test: DragAndDropTests.DropPreviewForImageInEditableArea

* loader/EmptyClients.h:
* page/ChromeClient.h:
* page/Page.cpp:
(WebCore::Page::didFinishLoadingImageForElement):
* page/Page.h:
* rendering/RenderImage.cpp:
(WebCore::RenderImage::notifyFinished):

Source/WebKit:

Adds support for targeted drop animations on iOS in modern WebKit by adopting UIKit SPI introduced in
<rdar://problem/31075005> to allow updating the drop preview mid-flight. To get the animation right, we refactor
and augment existing logic for taking snapshots after performing a drop in an editable content.

Currently, upon dropping in editable content, we first snapshot the web view and temporarily cover the real web
view with this snapshot. When the TextIndicator data arrives that contains (1) a snapshot of the visible part of
the web view ignoring the selection, and (2) a snapshot of just the selected contents after drop, we crossfade
from the web view snapshot to the snapshot in (1) using a hard-coded time delay (~500ms), and target the drop
preview to the drag caret rect. During this process, snapshot (2) is completely ignored.

This was effectively a halfway implemention of the desired effect of animating the dropped content into place
and crossfading to the final content; before UIKit implemented updateable drag previews, the full implementation
was not possible in modern WebKit (without using synchronous IPC).

Now that we're able to update the drag preview in the middle of the drop animation, we can now utilize snapshot
(2) above and clean up some parts of the drop animation in editable content. See below for more details.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _doAfterReceivingEditDragSnapshotForTesting:]):

Add a testing hook to perform the given block after any pending edit drag snapshot has been received. See
TestWebKitAPI changes for more detail.

* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:

Split up the existing DidConcludeEditDrag IPC message into two messages: WillReceiveEditDragSnapshot and
DidReceiveEditDragSnapshot. This allows us to defer cleaning up the drag session state during an edit drop,
until after the final edit drag snapshot has been received.

* UIProcess/ios/DragDropInteractionState.h:

Add some new methods to help manage the lifecycle of drop preview provider blocks.

* UIProcess/ios/DragDropInteractionState.mm:
(WebKit::createTargetedDragPreview):

Drive-by fix: make this return a RetainPtr.

(WebKit::DragDropInteractionState::prepareForDelayedDropPreview):

Stores a drop preview provider, given to us by UIKit.

(WebKit::DragDropInteractionState::deliverDelayedDropPreview):

Invokes the stored drop preview providers with given text indicator data. This is invoked after snapshots are
taken following an edit drag (this is additionally after all images in the inserted fragment have finished
loading).

(WebKit::DragDropInteractionState::clearAllDelayedItemPreviewProviders):

Invokes all stored drop preview providers with a nil preview. This is invoked in any case where drag session
cleanup occurs earlier than normal (e.g., if the web process crashes during drop), and ensures that the handlers
are always invoked when cleaning up the drag session.

(WebKit::DragDropInteractionState::previewForDragItem const):
(WebKit::DragDropInteractionState::dragAndDropSessionsDidEnd):

Call clearAllDelayedItemPreviewProviders.

* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::willReceiveEditDragSnapshot):
(WebKit::PageClientImpl::didReceiveEditDragSnapshot):
(WebKit::PageClientImpl::didConcludeEditDrag): Deleted.

More plumbing (see changes to DidConcludeEditDrag above).

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cleanupInteraction]):
(-[WKContentView cleanUpDragSourceSessionState]):
(-[WKContentView _willReceiveEditDragSnapshot]):
(-[WKContentView _didReceiveEditDragSnapshot:]):

Set _waitingForEditDragSnapshot to YES in the gap between when -_willReceiveEditDragSnapshot is invoked, and
when -_didReceiveEditDragSnapshot is invoked. If _waitingForEditDragSnapshot is YES, we bail out of
-cleanUpDragSourceSessionState, and instead clean up drag session state after the edit drag snapshot is
received.

(-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
(-[WKContentView _didPerformDragOperation:]):
(-[WKContentView textEffectsWindow]):

Drive-by fix to remove a workaround for a deprecation warning.

(-[WKContentView dropInteraction:item:willAnimateDropWithAnimator:]):
(-[WKContentView dropInteraction:concludeDrop:]):

Implement this hook to ensure that the unselected content snapshot view and visible content snapshot view are
guaranteed to be removed from the view after a drop in editable content, even if the drag edit snapshot arrives
after the drop is concluded.

(-[WKContentView dropInteraction:previewForDroppingItem:withDefault:]):
(-[WKContentView _dropInteraction:delayedPreviewProviderForDroppingItem:previewProvider:]):

Implement the new UIKit SPI here. UIKit hands us a preview provider here, which we can invoke at a later time
to update the drop preview. We do this in _didReceiveEditDragSnapshot.

(-[WKContentView _doAfterReceivingEditDragSnapshotForTesting:]):
(-[WKContentView _didConcludeEditDrag:]): Deleted.
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::willReceiveEditDragSnapshot):
(WebKit::WebPageProxy::didReceiveEditDragSnapshot):
(WebKit::WebPageProxy::didConcludeDrop):
(WebKit::WebPageProxy::didConcludeEditDrag): Deleted.
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::didFinishLoadingImageForElement):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didFinishLoadingImageForElement):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::didConcludeDrop):

If an edit drag has been concluded, there's no need to hang on to pending dropped image elements anymore; clear
out the set here.

(WebKit::WebPage::didConcludeEditDrag):

After concluding an edit drag, we try to deliver two web content snapshots to the UI process, so that the UI
process can assemble a targeted drop preview for UIKit. One snapshot is of the visible content area, not
including any selected content. The other snapshot is of the selected content only. However, when dropping
images (or a text selection containing images), these images may not yet have been loaded. If that is the case,
these images will appear to be missing from these snapshots.

To ensure that we don't take this snapshot too early, defer it until all image elements in the dropped content
range have finished loading. We can tell that all dropped images have finished loading by using a new client
hook that is invoked when an image has finished loading.

(WebKit::WebPage::didFinishLoadingImageForElement):
(WebKit::WebPage::computeAndSendEditDragSnapshot):

Snapshot the selected content and send it to the UI process.

Source/WebKitLegacy/mac:

Add a new chrome client method. See other changelogs for more detail.

* WebCoreSupport/WebChromeClient.h:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::didFinishLoadingImageForElement):

Source/WebKitLegacy/win:

* WebCoreSupport/WebChromeClient.cpp:
(WebChromeClient::didFinishLoadingImageForElement):
* WebCoreSupport/WebChromeClient.h:

Tools:

Adjusts the iOS dragging simulator, and adds a new API test. See below for more detail.

* TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
(TestWebKitAPI::isCompletelyWhite):
(TestWebKitAPI::TEST):

Add a test that drags and drops an image into a contenteditable element, and then observes the resulting
UITargetedDragPreviews upon drop.

* TestWebKitAPI/cocoa/DragAndDropSimulator.h:
* TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
(-[DragAndDropSimulator _resetSimulatedState]):
(-[DragAndDropSimulator runFrom:to:additionalItemRequestLocations:]):
(-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):

Teach the iOS version of DragAndDropSimulator to invoke -dropInteraction:concludeDrop: on the drop interaction
delegate when the drop finishes. This additionally uses _doAfterReceivingEditDragSnapshotForTesting: to defer
the end of the simulated drag and drop until after drag previews have been received during an edit drag.

(-[DragAndDropSimulator dropPreviews]):
(-[DragAndDropSimulator delayedDropPreviews]):

Have the drag and drop simulator remember which previews were returned by the delegate on drop, as well as which
previews were provided asynchronously.

(-[DragAndDropSimulator _webView:dataInteractionOperationWasHandled:forSession:itemProviders:]):
* TestWebKitAPI/ios/UIKitSPI.h:

Stage the new private drop interacton delegate method.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (245777 => 245778)


--- trunk/Source/WebCore/ChangeLog	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/ChangeLog	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1,3 +1,24 @@
+2019-05-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Dropped text, attachments, and images should animate into place
+        https://bugs.webkit.org/show_bug.cgi?id=198243
+        <rdar://problem/35205373>
+
+        Reviewed by Tim Horton.
+
+        Add some hooks to notify the chrome client when an HTMLImageElement's image is finished loading. See WebKit
+        changelog for more detail.
+
+        Test: DragAndDropTests.DropPreviewForImageInEditableArea
+
+        * loader/EmptyClients.h:
+        * page/ChromeClient.h:
+        * page/Page.cpp:
+        (WebCore::Page::didFinishLoadingImageForElement):
+        * page/Page.h:
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::notifyFinished):
+
 2019-05-25  Zalan Bujtas  <[email protected]>
 
         [LFC][IFC] Introduce DisplayRun to display tree

Modified: trunk/Source/WebCore/loader/EmptyClients.h (245777 => 245778)


--- trunk/Source/WebCore/loader/EmptyClients.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/loader/EmptyClients.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -40,6 +40,7 @@
 
 class DiagnosticLoggingClient;
 class EditorClient;
+class HTMLImageElement;
 class PageConfiguration;
 
 class EmptyChromeClient : public ChromeClient {
@@ -111,6 +112,8 @@
     IntPoint accessibilityScreenToRootView(const IntPoint& p) const final { return p; };
     IntRect rootViewToAccessibilityScreen(const IntRect& r) const final { return r; };
 
+    void didFinishLoadingImageForElement(HTMLImageElement&) final { }
+
     PlatformPageClient platformPageClient() const final { return 0; }
     void contentsSizeChanged(Frame&, const IntSize&) const final { }
     void intrinsicContentsSizeChanged(const IntSize&) const final { }

Modified: trunk/Source/WebCore/page/ChromeClient.h (245777 => 245778)


--- trunk/Source/WebCore/page/ChromeClient.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/page/ChromeClient.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -87,6 +87,7 @@
 class Geolocation;
 class GraphicsLayer;
 class GraphicsLayerFactory;
+class HTMLImageElement;
 class HTMLInputElement;
 class HTMLMediaElement;
 class HTMLVideoElement;
@@ -182,6 +183,8 @@
     virtual IntPoint accessibilityScreenToRootView(const IntPoint&) const = 0;
     virtual IntRect rootViewToAccessibilityScreen(const IntRect&) const = 0;
 
+    virtual void didFinishLoadingImageForElement(HTMLImageElement&) = 0;
+
     virtual PlatformPageClient platformPageClient() const = 0;
 
 #if ENABLE(CURSOR_SUPPORT)

Modified: trunk/Source/WebCore/page/Page.cpp (245777 => 245778)


--- trunk/Source/WebCore/page/Page.cpp	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/page/Page.cpp	2019-05-26 11:31:49 UTC (rev 245778)
@@ -2996,4 +2996,9 @@
 #endif
 }
 
+void Page::didFinishLoadingImageForElement(HTMLImageElement& element)
+{
+    chrome().client().didFinishLoadingImageForElement(element);
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/Page.h (245777 => 245778)


--- trunk/Source/WebCore/page/Page.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/page/Page.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -527,6 +527,8 @@
     WEBCORE_EXPORT VisibilityState visibilityState() const;
     WEBCORE_EXPORT void resumeAnimatingImages();
 
+    void didFinishLoadingImageForElement(HTMLImageElement&);
+
     WEBCORE_EXPORT void addLayoutMilestones(OptionSet<LayoutMilestone>);
     WEBCORE_EXPORT void removeLayoutMilestones(OptionSet<LayoutMilestone>);
     OptionSet<LayoutMilestone> requestedLayoutMilestones() const { return m_requestedLayoutMilestones; }

Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (245777 => 245778)


--- trunk/Source/WebCore/rendering/RenderImage.cpp	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp	2019-05-26 11:31:49 UTC (rev 245778)
@@ -378,6 +378,9 @@
         // that the image is done and they can reference it directly.
         contentChanged(ImageChanged);
     }
+
+    if (is<HTMLImageElement>(element()))
+        page().didFinishLoadingImageForElement(downcast<HTMLImageElement>(*element()));
 }
 
 bool RenderImage::isShowingMissingOrImageError() const

Modified: trunk/Source/WebKit/ChangeLog (245777 => 245778)


--- trunk/Source/WebKit/ChangeLog	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/ChangeLog	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1,3 +1,149 @@
+2019-05-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Dropped text, attachments, and images should animate into place
+        https://bugs.webkit.org/show_bug.cgi?id=198243
+        <rdar://problem/35205373>
+
+        Reviewed by Tim Horton.
+
+        Adds support for targeted drop animations on iOS in modern WebKit by adopting UIKit SPI introduced in
+        <rdar://problem/31075005> to allow updating the drop preview mid-flight. To get the animation right, we refactor
+        and augment existing logic for taking snapshots after performing a drop in an editable content.
+
+        Currently, upon dropping in editable content, we first snapshot the web view and temporarily cover the real web
+        view with this snapshot. When the TextIndicator data arrives that contains (1) a snapshot of the visible part of
+        the web view ignoring the selection, and (2) a snapshot of just the selected contents after drop, we crossfade
+        from the web view snapshot to the snapshot in (1) using a hard-coded time delay (~500ms), and target the drop
+        preview to the drag caret rect. During this process, snapshot (2) is completely ignored.
+
+        This was effectively a halfway implemention of the desired effect of animating the dropped content into place
+        and crossfading to the final content; before UIKit implemented updateable drag previews, the full implementation
+        was not possible in modern WebKit (without using synchronous IPC).
+
+        Now that we're able to update the drag preview in the middle of the drop animation, we can now utilize snapshot
+        (2) above and clean up some parts of the drop animation in editable content. See below for more details.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView _doAfterReceivingEditDragSnapshotForTesting:]):
+
+        Add a testing hook to perform the given block after any pending edit drag snapshot has been received. See
+        TestWebKitAPI changes for more detail.
+
+        * UIProcess/API/Cocoa/WKWebViewPrivate.h:
+        * UIProcess/PageClient.h:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+
+        Split up the existing DidConcludeEditDrag IPC message into two messages: WillReceiveEditDragSnapshot and
+        DidReceiveEditDragSnapshot. This allows us to defer cleaning up the drag session state during an edit drop,
+        until after the final edit drag snapshot has been received.
+
+        * UIProcess/ios/DragDropInteractionState.h:
+
+        Add some new methods to help manage the lifecycle of drop preview provider blocks.
+
+        * UIProcess/ios/DragDropInteractionState.mm:
+        (WebKit::createTargetedDragPreview):
+
+        Drive-by fix: make this return a RetainPtr.
+
+        (WebKit::DragDropInteractionState::prepareForDelayedDropPreview):
+
+        Stores a drop preview provider, given to us by UIKit.
+
+        (WebKit::DragDropInteractionState::deliverDelayedDropPreview):
+
+        Invokes the stored drop preview providers with given text indicator data. This is invoked after snapshots are
+        taken following an edit drag (this is additionally after all images in the inserted fragment have finished
+        loading).
+
+        (WebKit::DragDropInteractionState::clearAllDelayedItemPreviewProviders):
+
+        Invokes all stored drop preview providers with a nil preview. This is invoked in any case where drag session
+        cleanup occurs earlier than normal (e.g., if the web process crashes during drop), and ensures that the handlers
+        are always invoked when cleaning up the drag session.
+
+        (WebKit::DragDropInteractionState::previewForDragItem const):
+        (WebKit::DragDropInteractionState::dragAndDropSessionsDidEnd):
+
+        Call clearAllDelayedItemPreviewProviders.
+
+        * UIProcess/ios/PageClientImplIOS.h:
+        * UIProcess/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::willReceiveEditDragSnapshot):
+        (WebKit::PageClientImpl::didReceiveEditDragSnapshot):
+        (WebKit::PageClientImpl::didConcludeEditDrag): Deleted.
+
+        More plumbing (see changes to DidConcludeEditDrag above).
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView cleanupInteraction]):
+        (-[WKContentView cleanUpDragSourceSessionState]):
+        (-[WKContentView _willReceiveEditDragSnapshot]):
+        (-[WKContentView _didReceiveEditDragSnapshot:]):
+
+        Set _waitingForEditDragSnapshot to YES in the gap between when -_willReceiveEditDragSnapshot is invoked, and
+        when -_didReceiveEditDragSnapshot is invoked. If _waitingForEditDragSnapshot is YES, we bail out of
+        -cleanUpDragSourceSessionState, and instead clean up drag session state after the edit drag snapshot is
+        received.
+
+        (-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
+        (-[WKContentView _didPerformDragOperation:]):
+        (-[WKContentView textEffectsWindow]):
+
+        Drive-by fix to remove a workaround for a deprecation warning.
+
+        (-[WKContentView dropInteraction:item:willAnimateDropWithAnimator:]):
+        (-[WKContentView dropInteraction:concludeDrop:]):
+
+        Implement this hook to ensure that the unselected content snapshot view and visible content snapshot view are
+        guaranteed to be removed from the view after a drop in editable content, even if the drag edit snapshot arrives
+        after the drop is concluded.
+
+        (-[WKContentView dropInteraction:previewForDroppingItem:withDefault:]):
+        (-[WKContentView _dropInteraction:delayedPreviewProviderForDroppingItem:previewProvider:]):
+
+        Implement the new UIKit SPI here. UIKit hands us a preview provider here, which we can invoke at a later time
+        to update the drop preview. We do this in _didReceiveEditDragSnapshot.
+
+        (-[WKContentView _doAfterReceivingEditDragSnapshotForTesting:]):
+        (-[WKContentView _didConcludeEditDrag:]): Deleted.
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::willReceiveEditDragSnapshot):
+        (WebKit::WebPageProxy::didReceiveEditDragSnapshot):
+        (WebKit::WebPageProxy::didConcludeDrop):
+        (WebKit::WebPageProxy::didConcludeEditDrag): Deleted.
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::didFinishLoadingImageForElement):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::didFinishLoadingImageForElement):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::didConcludeDrop):
+
+        If an edit drag has been concluded, there's no need to hang on to pending dropped image elements anymore; clear
+        out the set here.
+
+        (WebKit::WebPage::didConcludeEditDrag):
+
+        After concluding an edit drag, we try to deliver two web content snapshots to the UI process, so that the UI
+        process can assemble a targeted drop preview for UIKit. One snapshot is of the visible content area, not
+        including any selected content. The other snapshot is of the selected content only. However, when dropping
+        images (or a text selection containing images), these images may not yet have been loaded. If that is the case,
+        these images will appear to be missing from these snapshots.
+
+        To ensure that we don't take this snapshot too early, defer it until all image elements in the dropped content
+        range have finished loading. We can tell that all dropped images have finished loading by using a new client
+        hook that is invoked when an image has finished loading.
+
+        (WebKit::WebPage::didFinishLoadingImageForElement):
+        (WebKit::WebPage::computeAndSendEditDragSnapshot):
+
+        Snapshot the selected content and send it to the UI process.
+
 2019-05-24  Youenn Fablet  <[email protected]>
 
         REGRESSION (r245715?) [WK2] Layout Test http/wpt/cache-storage/cache-storage-networkprocess-crash.html is a flaky failure

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -6889,6 +6889,11 @@
     };
 }
 
+- (void)_doAfterReceivingEditDragSnapshotForTesting:(dispatch_block_t)action
+{
+    [_contentView _doAfterReceivingEditDragSnapshotForTesting:action];
+}
+
 #endif // PLATFORM(IOS_FAMILY)
 
 #if PLATFORM(MAC)

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -489,6 +489,8 @@
 
 @property (nonatomic, readonly) CGRect _dragCaretRect WK_API_AVAILABLE(ios(11.0));
 
+- (void)_doAfterReceivingEditDragSnapshotForTesting:(dispatch_block_t)action WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
 - (void)_requestActivatedElementAtPosition:(CGPoint)position completionBlock:(void (^)(_WKActivatedElementInfo *))block WK_API_AVAILABLE(ios(11.0));
 - (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text completionHandler:(void (^)(NSArray<NSValue *> *rects))completionHandler WK_API_AVAILABLE(ios(11.3));
 - (void)_accessibilityStoreSelection WK_API_AVAILABLE(ios(11.3));

Modified: trunk/Source/WebKit/UIProcess/PageClient.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/PageClient.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/PageClient.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -479,7 +479,8 @@
 #if ENABLE(DATA_INTERACTION)
     virtual void didHandleDragStartRequest(bool started) = 0;
     virtual void didHandleAdditionalDragItemsRequest(bool added) = 0;
-    virtual void didConcludeEditDrag(Optional<WebCore::TextIndicatorData>) = 0;
+    virtual void willReceiveEditDragSnapshot() = 0;
+    virtual void didReceiveEditDragSnapshot(Optional<WebCore::TextIndicatorData>) = 0;
     virtual void didChangeDragCaretRect(const WebCore::IntRect& previousCaretRect, const WebCore::IntRect& caretRect) = 0;
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -726,12 +726,14 @@
     void updateSelectionWithDelta(int64_t locationDelta, int64_t lengthDelta, CompletionHandler<void()>&&);
     void requestDocumentEditingContext(WebKit::DocumentEditingContextRequest, CompletionHandler<void(WebKit::DocumentEditingContext)>&&);
     void generateSyntheticEditingCommand(SyntheticEditingCommandType);
-#if ENABLE(DATA_INTERACTION)
+#if ENABLE(DRAG_SUPPORT)
     void didHandleDragStartRequest(bool started);
     void didHandleAdditionalDragItemsRequest(bool added);
     void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, WebCore::DragSourceAction allowedActions);
     void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, WebCore::DragSourceAction allowedActions);
-    void didConcludeEditDrag(Optional<WebCore::TextIndicatorData>);
+    void willReceiveEditDragSnapshot();
+    void didReceiveEditDragSnapshot(Optional<WebCore::TextIndicatorData>);
+    void didConcludeDrop();
 #endif
 #endif // PLATFORM(IOS_FAMILY)
 #if ENABLE(DATA_DETECTION)

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2019-05-26 11:31:49 UTC (rev 245778)
@@ -333,7 +333,8 @@
 #if ENABLE(DATA_INTERACTION)
     DidHandleDragStartRequest(bool started)
     DidHandleAdditionalDragItemsRequest(bool added)
-    DidConcludeEditDrag(Optional<WebCore::TextIndicatorData> textIndicator)
+    WillReceiveEditDragSnapshot()
+    DidReceiveEditDragSnapshot(Optional<WebCore::TextIndicatorData> textIndicator)
 #endif
 
 #if PLATFORM(COCOA)

Modified: trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -40,6 +40,7 @@
 
 namespace WebCore {
 struct DragItem;
+struct TextIndicatorData;
 }
 
 namespace WebKit {
@@ -58,6 +59,11 @@
     NSInteger itemIdentifier { 0 };
 };
 
+struct ItemAndPreviewProvider {
+    RetainPtr<UIDragItem> item;
+    BlockPtr<void(UITargetedDragPreview *)> provider;
+};
+
 class DragDropInteractionState {
 public:
     bool anyActiveDragSourceIs(WebCore::DragSourceAction) const;
@@ -92,6 +98,10 @@
     BlockPtr<void()> takeDragCancelSetDownBlock() { return WTFMove(m_dragCancelSetDownBlock); }
     BlockPtr<void(NSArray<UIDragItem *> *)> takeAddDragItemCompletionBlock() { return WTFMove(m_addDragItemCompletionBlock); }
 
+    void prepareForDelayedDropPreview(UIDragItem *, void(^provider)(UITargetedDragPreview *preview));
+    void deliverDelayedDropPreview(UIView *contentView, UIView *previewContainer, const WebCore::TextIndicatorData&);
+    void clearAllDelayedItemPreviewProviders();
+
 private:
     void updatePreviewsForActiveDragSources();
     Optional<DragSourceState> activeDragSourceForItem(UIDragItem *) const;
@@ -108,6 +118,7 @@
 
     Optional<DragSourceState> m_stagedDragSource;
     Vector<DragSourceState> m_activeDragSources;
+    Vector<ItemAndPreviewProvider> m_delayedItemPreviewProviders;
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -44,7 +44,7 @@
     return nil;
 }
 
-static UITargetedDragPreview *createTargetedDragPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const FloatRect& frameInRootViewCoordinates, const Vector<FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor, UIBezierPath *visiblePath)
+static RetainPtr<UITargetedDragPreview> createTargetedDragPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const FloatRect& frameInRootViewCoordinates, const Vector<FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor, UIBezierPath *visiblePath)
 {
     if (frameInRootViewCoordinates.isEmpty() || !image)
         return nullptr;
@@ -78,8 +78,7 @@
 
     CGPoint centerInContainerCoordinates = { CGRectGetMidX(frameInContainerCoordinates), CGRectGetMidY(frameInContainerCoordinates) };
     auto target = adoptNS([[UIDragPreviewTarget alloc] initWithContainer:previewContainer center:centerInContainerCoordinates]);
-    auto dragPreview = adoptNS([[UITargetedDragPreview alloc] initWithView:imageView.get() parameters:parameters.get() target:target.get()]);
-    return dragPreview.autorelease();
+    return adoptNS([[UITargetedDragPreview alloc] initWithView:imageView.get() parameters:parameters.get() target:target.get()]);
 }
 
 static RetainPtr<UIImage> uiImageForImage(Image* image)
@@ -186,6 +185,30 @@
     updatePreviewsForActiveDragSources();
 }
 
+void DragDropInteractionState::prepareForDelayedDropPreview(UIDragItem *item, void(^provider)(UITargetedDragPreview *preview))
+{
+    m_delayedItemPreviewProviders.append({ item, provider });
+}
+
+void DragDropInteractionState::deliverDelayedDropPreview(UIView *contentView, UIView *previewContainer, const WebCore::TextIndicatorData& indicator)
+{
+    if (m_delayedItemPreviewProviders.isEmpty())
+        return;
+
+    auto textIndicatorImage = uiImageForImage(indicator.contentImage.get());
+    auto preview = createTargetedDragPreview(textIndicatorImage.get(), contentView, previewContainer, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)], nil);
+    for (auto& itemAndPreviewProvider : m_delayedItemPreviewProviders)
+        itemAndPreviewProvider.provider(preview.get());
+    m_delayedItemPreviewProviders.clear();
+}
+
+void DragDropInteractionState::clearAllDelayedItemPreviewProviders()
+{
+    for (auto& itemAndPreviewProvider : m_delayedItemPreviewProviders)
+        itemAndPreviewProvider.provider(nil);
+    m_delayedItemPreviewProviders.clear();
+}
+
 UITargetedDragPreview *DragDropInteractionState::previewForDragItem(UIDragItem *item, UIView *contentView, UIView *previewContainer) const
 {
     auto foundSource = activeDragSourceForItem(item);
@@ -197,15 +220,15 @@
         if (shouldUseVisiblePathToCreatePreviewForDragSource(source)) {
             auto path = source.visiblePath.value();
             UIBezierPath *visiblePath = [UIBezierPath bezierPathWithCGPath:path.ensurePlatformPath()];
-            return createTargetedDragPreview(source.image.get(), contentView, previewContainer, source.dragPreviewFrameInRootViewCoordinates, { }, nil, visiblePath);
+            return createTargetedDragPreview(source.image.get(), contentView, previewContainer, source.dragPreviewFrameInRootViewCoordinates, { }, nil, visiblePath).autorelease();
         }
-        return createTargetedDragPreview(source.image.get(), contentView, previewContainer, source.dragPreviewFrameInRootViewCoordinates, { }, nil, nil);
+        return createTargetedDragPreview(source.image.get(), contentView, previewContainer, source.dragPreviewFrameInRootViewCoordinates, { }, nil, nil).autorelease();
     }
 
     if (shouldUseTextIndicatorToCreatePreviewForDragSource(source)) {
         auto indicator = source.indicatorData.value();
         auto textIndicatorImage = uiImageForImage(indicator.contentImage.get());
-        return createTargetedDragPreview(textIndicatorImage.get(), contentView, previewContainer, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)], nil);
+        return createTargetedDragPreview(textIndicatorImage.get(), contentView, previewContainer, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)], nil).autorelease();
     }
 
     return nil;
@@ -266,6 +289,8 @@
 
 void DragDropInteractionState::dragAndDropSessionsDidEnd()
 {
+    clearAllDelayedItemPreviewProviders();
+
     // If any of UIKit's completion blocks are still in-flight when the drag interaction ends, we need to ensure that they are still invoked
     // to prevent UIKit from getting into an inconsistent state.
     if (auto completionBlock = takeDragCancelSetDownBlock())

Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -237,7 +237,8 @@
     void didHandleDragStartRequest(bool started) override;
     void didHandleAdditionalDragItemsRequest(bool added) override;
     void startDrag(const WebCore::DragItem&, const ShareableBitmap::Handle& image) override;
-    void didConcludeEditDrag(Optional<WebCore::TextIndicatorData>) override;
+    void willReceiveEditDragSnapshot() override;
+    void didReceiveEditDragSnapshot(Optional<WebCore::TextIndicatorData>) override;
     void didChangeDragCaretRect(const WebCore::IntRect& previousCaretRect, const WebCore::IntRect& caretRect) override;
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -820,11 +820,16 @@
     [m_contentView _startDrag:ShareableBitmap::create(image)->makeCGImageCopy() item:item];
 }
 
-void PageClientImpl::didConcludeEditDrag(Optional<TextIndicatorData> data)
+void PageClientImpl::willReceiveEditDragSnapshot()
 {
-    [m_contentView _didConcludeEditDrag:data];
+    [m_contentView _willReceiveEditDragSnapshot];
 }
 
+void PageClientImpl::didReceiveEditDragSnapshot(Optional<TextIndicatorData> data)
+{
+    [m_contentView _didReceiveEditDragSnapshot:data];
+}
+
 void PageClientImpl::didChangeDragCaretRect(const IntRect& previousCaretRect, const IntRect& caretRect)
 {
     [m_contentView _didChangeDragCaretRect:previousCaretRect currentRect:caretRect];

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -334,6 +334,7 @@
     BOOL _isBlurringFocusedElement;
 
     BOOL _focusRequiresStrongPasswordAssistance;
+    BOOL _waitingForEditDragSnapshot;
 
     BOOL _hasSetUpInteractions;
     NSUInteger _ignoreSelectionCommandFadeCount;
@@ -345,9 +346,10 @@
     RetainPtr<UIDragInteraction> _dragInteraction;
     RetainPtr<UIDropInteraction> _dropInteraction;
     BOOL _shouldRestoreCalloutBarAfterDrop;
-    BOOL _isAnimatingConcludeEditDrag;
     RetainPtr<UIView> _visibleContentViewSnapshot;
+    RetainPtr<UIView> _unselectedContentSnapshot;
     RetainPtr<_UITextDragCaretView> _editDropCaretView;
+    BlockPtr<void()> _actionToPerformAfterReceivingEditDragSnapshot;
 #endif
 
 #if PLATFORM(WATCHOS)
@@ -490,7 +492,8 @@
 - (void)_didHandleDragStartRequest:(BOOL)started;
 - (void)_didHandleAdditionalDragItemsRequest:(BOOL)added;
 - (void)_startDrag:(RetainPtr<CGImageRef>)image item:(const WebCore::DragItem&)item;
-- (void)_didConcludeEditDrag:(Optional<WebCore::TextIndicatorData>)data;
+- (void)_willReceiveEditDragSnapshot;
+- (void)_didReceiveEditDragSnapshot:(Optional<WebCore::TextIndicatorData>)data;
 - (void)_didChangeDragCaretRect:(CGRect)previousRect currentRect:(CGRect)rect;
 #endif
 
@@ -517,6 +520,7 @@
 - (void)selectFormAccessoryPickerRow:(NSInteger)rowIndex;
 - (void)setTimePickerValueToHour:(NSInteger)hour minute:(NSInteger)minute;
 - (NSDictionary *)_contentsOfUserInterfaceItem:(NSString *)userInterfaceItem;
+- (void)_doAfterReceivingEditDragSnapshotForTesting:(dispatch_block_t)action;
 
 @property (nonatomic, readonly) NSString *textContentTypeForTesting;
 @property (nonatomic, readonly) NSString *selectFormPopoverTitle;

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -841,6 +841,7 @@
     _outstandingPositionInformationRequest = WTF::nullopt;
 
     _focusRequiresStrongPasswordAssistance = NO;
+    _waitingForEditDragSnapshot = NO;
 
 #if USE(UIKIT_KEYBOARD_ADDITIONS)
     _candidateViewNeedsUpdate = NO;
@@ -6269,6 +6270,9 @@
 
 - (void)cleanUpDragSourceSessionState
 {
+    if (_waitingForEditDragSnapshot)
+        return;
+
     if (_dragDropInteractionState.dragSession() || _dragDropInteractionState.isPerformingDrop())
         RELEASE_LOG(DragAndDrop, "Cleaning up dragging state (has pending operation: %d)", [[WebItemProviderPasteboard sharedInstance] hasPendingOperation]);
 
@@ -6281,11 +6285,9 @@
     [[WebItemProviderPasteboard sharedInstance] stageRegistrationList:nil];
     [self _restoreCalloutBarIfNeeded];
 
-    [_visibleContentViewSnapshot removeFromSuperview];
-    _visibleContentViewSnapshot = nil;
+    [std::exchange(_visibleContentViewSnapshot, nil) removeFromSuperview];
     [_editDropCaretView remove];
     _editDropCaretView = nil;
-    _isAnimatingConcludeEditDrag = NO;
     _shouldRestoreCalloutBarAfterDrop = NO;
 
     _dragDropInteractionState.dragAndDropSessionsDidEnd();
@@ -6307,11 +6309,33 @@
     return extractItemProvidersFromDragItems(session.items);
 }
 
-- (void)_didConcludeEditDrag:(Optional<WebCore::TextIndicatorData>)data
+- (void)_willReceiveEditDragSnapshot
 {
+    _waitingForEditDragSnapshot = YES;
+}
+
+- (void)_didReceiveEditDragSnapshot:(Optional<WebCore::TextIndicatorData>)data
+{
+    _waitingForEditDragSnapshot = NO;
+
+    [self _deliverDelayedDropPreviewIfPossible:data];
+    [self cleanUpDragSourceSessionState];
+
+    if (auto action = ""
+        action();
+}
+
+- (void)_deliverDelayedDropPreviewIfPossible:(Optional<WebCore::TextIndicatorData>)data
+{
+    if (!_visibleContentViewSnapshot)
+        return;
+
     if (!data)
         return;
 
+    if (!data->contentImage)
+        return;
+
     auto snapshotWithoutSelection = data->contentImageWithoutSelection;
     if (!snapshotWithoutSelection)
         return;
@@ -6321,25 +6345,11 @@
         return;
 
     auto unselectedContentImageForEditDrag = adoptNS([[UIImage alloc] initWithCGImage:unselectedSnapshotImage.get() scale:_page->deviceScaleFactor() orientation:UIImageOrientationUp]);
-    auto unselectedContentSnapshot = adoptNS([[UIImageView alloc] initWithImage:unselectedContentImageForEditDrag.get()]);
-    [unselectedContentSnapshot setFrame:data->contentImageWithoutSelectionRectInRootViewCoordinates];
+    _unselectedContentSnapshot = adoptNS([[UIImageView alloc] initWithImage:unselectedContentImageForEditDrag.get()]);
+    [_unselectedContentSnapshot setFrame:data->contentImageWithoutSelectionRectInRootViewCoordinates];
 
-    auto protectedSelf = retainPtr(self);
-    auto visibleContentViewSnapshot = adoptNS(_visibleContentViewSnapshot.leakRef());
-
-    _isAnimatingConcludeEditDrag = YES;
-    [self insertSubview:unselectedContentSnapshot.get() belowSubview:visibleContentViewSnapshot.get()];
-    [UIView animateWithDuration:0.25 animations:^() {
-        [visibleContentViewSnapshot setAlpha:0];
-    } completion:^(BOOL completed) {
-        [visibleContentViewSnapshot removeFromSuperview];
-        [UIView animateWithDuration:0.25 animations:^() {
-            [protectedSelf _stopSuppressingSelectionAssistantForReason:WebKit::DropAnimationIsRunning];
-            [unselectedContentSnapshot setAlpha:0];
-        } completion:^(BOOL completed) {
-            [unselectedContentSnapshot removeFromSuperview];
-        }];
-    }];
+    [self insertSubview:_unselectedContentSnapshot.get() belowSubview:_visibleContentViewSnapshot.get()];
+    _dragDropInteractionState.deliverDelayedDropPreview(self, self.unscaledView, data.value());
 }
 
 - (void)_didPerformDragOperation:(BOOL)handled
@@ -6350,9 +6360,6 @@
     if ([self.webViewUIDelegate respondsToSelector:@selector(_webView:dataInteractionOperationWasHandled:forSession:itemProviders:)])
         [self.webViewUIDelegate _webView:_webView dataInteractionOperationWasHandled:handled forSession:dropSession itemProviders:[WebItemProviderPasteboard sharedInstance].itemProviders];
 
-    if (!_isAnimatingConcludeEditDrag)
-        [self _stopSuppressingSelectionAssistantForReason:WebKit::DropAnimationIsRunning];
-
     CGPoint global;
     CGPoint client;
     [self computeClientAndGlobalPointsForDropSession:dropSession outClientPoint:&client outGlobalPoint:&global];
@@ -6509,6 +6516,15 @@
     return dragItems;
 }
 
+- (UIView *)textEffectsWindow
+{
+#if HAVE(UISCENE)
+    return [UITextEffectsWindow sharedTextEffectsWindowForWindowScene:self.window.windowScene];
+#else
+    return [UITextEffectsWindow sharedTextEffectsWindow];
+#endif
+}
+
 - (NSDictionary *)_autofillContext
 {
     BOOL provideStrongPasswordAssistance = _focusRequiresStrongPasswordAssistance && _focusedElementInformation.elementType == WebKit::InputType::Password;
@@ -6890,6 +6906,22 @@
     }];
 }
 
+- (void)dropInteraction:(UIDropInteraction *)interaction item:(UIDragItem *)item willAnimateDropWithAnimator:(id <UIDragAnimating>)animator
+{
+    [animator addCompletion:[strongSelf = retainPtr(self)] (UIViewAnimatingPosition) {
+        [std::exchange(strongSelf->_unselectedContentSnapshot, nil) removeFromSuperview];
+    }];
+}
+
+- (void)dropInteraction:(UIDropInteraction *)interaction concludeDrop:(id <UIDropSession>)session
+{
+    [self _stopSuppressingSelectionAssistantForReason:WebKit::DropAnimationIsRunning];
+    [std::exchange(_visibleContentViewSnapshot, nil) removeFromSuperview];
+    [std::exchange(_unselectedContentSnapshot, nil) removeFromSuperview];
+    _dragDropInteractionState.clearAllDelayedItemPreviewProviders();
+    _page->didConcludeDrop();
+}
+
 - (UITargetedDragPreview *)dropInteraction:(UIDropInteraction *)interaction previewForDroppingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview
 {
     CGRect caretRect = _page->currentDragCaretRect();
@@ -6896,17 +6928,20 @@
     if (CGRectIsEmpty(caretRect))
         return nil;
 
-ALLOW_DEPRECATED_DECLARATIONS_BEGIN
-    // FIXME: <rdar://problem/31074376> [WK2] Performing an edit drag should transition from the initial drag preview to the final drop preview
-    // This is blocked on UIKit support, since we aren't able to update the text clipping rects of a UITargetedDragPreview mid-flight. For now,
-    // just zoom to the center of the caret rect while shrinking the drop preview.
-    auto caretRectInWindowCoordinates = [self convertRect:caretRect toView:[UITextEffectsWindow sharedTextEffectsWindow]];
+    UIView *textEffectsWindow = self.textEffectsWindow;
+    auto caretRectInWindowCoordinates = [self convertRect:caretRect toView:textEffectsWindow];
     auto caretCenterInWindowCoordinates = CGPointMake(CGRectGetMidX(caretRectInWindowCoordinates), CGRectGetMidY(caretRectInWindowCoordinates));
-    auto target = adoptNS([[UIDragPreviewTarget alloc] initWithContainer:[UITextEffectsWindow sharedTextEffectsWindow] center:caretCenterInWindowCoordinates transform:CGAffineTransformMakeScale(0, 0)]);
-ALLOW_DEPRECATED_DECLARATIONS_END
+    auto targetPreviewCenterInWindowCoordinates = CGPointMake(caretCenterInWindowCoordinates.x + defaultPreview.size.width / 2, caretCenterInWindowCoordinates.y + defaultPreview.size.height / 2);
+    auto target = adoptNS([[UIDragPreviewTarget alloc] initWithContainer:textEffectsWindow center:targetPreviewCenterInWindowCoordinates transform:CGAffineTransformIdentity]);
     return [defaultPreview retargetedPreviewWithTarget:target.get()];
 }
 
+- (void)_dropInteraction:(UIDropInteraction *)interaction delayedPreviewProviderForDroppingItem:(UIDragItem *)item previewProvider:(void(^)(UITargetedDragPreview *preview))previewProvider
+{
+    // FIXME: This doesn't currently handle multiple items in a drop session.
+    _dragDropInteractionState.prepareForDelayedDropPreview(item, previewProvider);
+}
+
 - (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnd:(id <UIDropSession>)session
 {
     RELEASE_LOG(DragAndDrop, "Drop session ended: %p (performing operation: %d, began dragging: %d)", session, _dragDropInteractionState.isPerformingDrop(), _dragDropInteractionState.didBeginDragging());
@@ -7166,6 +7201,18 @@
 
 @implementation WKContentView (WKTesting)
 
+- (void)_doAfterReceivingEditDragSnapshotForTesting:(dispatch_block_t)action
+{
+#if ENABLE(DRAG_SUPPORT)
+    ASSERT(!_actionToPerformAfterReceivingEditDragSnapshot);
+    if (_waitingForEditDragSnapshot) {
+        _actionToPerformAfterReceivingEditDragSnapshot = action;
+        return;
+    }
+#endif
+    action();
+}
+
 - (WKFormInputControl *)formInputControl
 {
     if ([_inputPeripheral isKindOfClass:WKFormInputControl.class])

Modified: trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm (245777 => 245778)


--- trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1219,11 +1219,21 @@
         m_process->send(Messages::WebPage::RequestAdditionalItemsForDragSession(clientPosition, globalPosition, allowedActions), m_pageID);
 }
 
-void WebPageProxy::didConcludeEditDrag(Optional<TextIndicatorData> data)
+void WebPageProxy::willReceiveEditDragSnapshot()
 {
-    pageClient().didConcludeEditDrag(data);
+    pageClient().willReceiveEditDragSnapshot();
 }
 
+void WebPageProxy::didReceiveEditDragSnapshot(Optional<TextIndicatorData> data)
+{
+    pageClient().didReceiveEditDragSnapshot(data);
+}
+
+void WebPageProxy::didConcludeDrop()
+{
+    m_process->send(Messages::WebPage::DidConcludeDrop(), m_pageID);
+}
+
 #endif
 
 #if USE(QUICK_LOOK)

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (245777 => 245778)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2019-05-26 11:31:49 UTC (rev 245778)
@@ -587,6 +587,11 @@
     return m_page.rootViewToAccessibilityScreen(rect);
 }
 
+void WebChromeClient::didFinishLoadingImageForElement(HTMLImageElement& element)
+{
+    m_page.didFinishLoadingImageForElement(element);
+}
+
 PlatformPageClient WebChromeClient::platformPageClient() const
 {
     notImplemented();

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (245777 => 245778)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -29,6 +29,7 @@
 #include <WebCore/ChromeClient.h>
 
 namespace WebCore {
+class HTMLImageElement;
 class RegistrableDomain;
 enum class StorageAccessPromptWasShown : bool;
 enum class StorageAccessWasGranted : bool;
@@ -121,6 +122,8 @@
     WebCore::IntPoint accessibilityScreenToRootView(const WebCore::IntPoint&) const final;
     WebCore::IntRect rootViewToAccessibilityScreen(const WebCore::IntRect&) const final;
 
+    void didFinishLoadingImageForElement(WebCore::HTMLImageElement&) final;
+
     PlatformPageClient platformPageClient() const final;
     void contentsSizeChanged(WebCore::Frame&, const WebCore::IntSize&) const final;
     void intrinsicContentsSizeChanged(const WebCore::IntSize&) const final;

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (245777 => 245778)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2019-05-26 11:31:49 UTC (rev 245778)
@@ -6740,6 +6740,14 @@
 }
 #endif
 
+#if !PLATFORM(IOS_FAMILY) || !ENABLE(DRAG_SUPPORT)
+
+void WebPage::didFinishLoadingImageForElement(WebCore::HTMLImageElement&)
+{
+}
+
+#endif
+
 } // namespace WebKit
 
 #undef RELEASE_LOG_IF_ALLOWED

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (245777 => 245778)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -154,6 +154,7 @@
 class FrameSelection;
 class FrameView;
 class GraphicsContext;
+class HTMLImageElement;
 class HTMLMenuElement;
 class HTMLMenuItemElement;
 class HTMLPlugInElement;
@@ -1113,10 +1114,13 @@
     void didGetLoadDecisionForIcon(bool decision, CallbackID loadIdentifier, OptionalCallbackID);
     void setUseIconLoadingClient(bool);
 
-#if ENABLE(DATA_INTERACTION)
+#if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT)
     void didConcludeEditDrag();
+    void didConcludeDrop();
 #endif
 
+    void didFinishLoadingImageForElement(WebCore::HTMLImageElement&);
+
     WebURLSchemeHandlerProxy* urlSchemeHandlerForScheme(const String&);
     void stopAllURLSchemeTasks();
 
@@ -1258,6 +1262,7 @@
 #if PLATFORM(IOS_FAMILY) && ENABLE(DATA_INTERACTION)
     void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t allowedActions);
     void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t allowedActions);
+    void computeAndSendEditDragSnapshot();
 #endif
 
 #if !PLATFORM(COCOA) && !PLATFORM(WPE)
@@ -1770,6 +1775,10 @@
     WebCore::DragSourceAction m_allowedDragSourceActions { WebCore::DragSourceActionAny };
 #endif
 
+#if ENABLE(DRAG_SUPPORT) && PLATFORM(IOS_FAMILY)
+    HashSet<RefPtr<WebCore::HTMLImageElement>> m_pendingImageElementsForDropSnapshot;
+#endif
+
     bool m_cachedMainFrameIsPinnedToLeftSide { true };
     bool m_cachedMainFrameIsPinnedToRightSide { true };
     bool m_cachedMainFrameIsPinnedToTopSide { true };

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (245777 => 245778)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2019-05-26 11:31:49 UTC (rev 245778)
@@ -303,9 +303,10 @@
     DragCancelled()
 #endif
 
-#if ENABLE(DATA_INTERACTION)
+#if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT)
     RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t allowedActions)
     RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t allowedActions)
+    DidConcludeDrop()
 #endif
 
     # Popup menu.

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


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -825,19 +825,63 @@
     send(Messages::WebPageProxy::DidHandleAdditionalDragItemsRequest(didHandleDrag));
 }
 
+void WebPage::didConcludeDrop()
+{
+    m_pendingImageElementsForDropSnapshot.clear();
+}
+
 void WebPage::didConcludeEditDrag()
 {
+    send(Messages::WebPageProxy::WillReceiveEditDragSnapshot());
+
+    layoutIfNeeded();
+
+    m_pendingImageElementsForDropSnapshot.clear();
+
+    bool waitingForAnyImageToLoad = false;
+    auto& frame = m_page->focusController().focusedOrMainFrame();
+    if (auto range = frame.selection().selection().toNormalizedRange()) {
+        for (TextIterator iterator(range.get()); !iterator.atEnd(); iterator.advance()) {
+            auto* node = iterator.node();
+            if (!is<HTMLImageElement>(node))
+                continue;
+
+            auto& imageElement = downcast<HTMLImageElement>(*node);
+            auto* cachedImage = imageElement.cachedImage();
+            if (cachedImage && cachedImage->image() && cachedImage->image()->isNull()) {
+                m_pendingImageElementsForDropSnapshot.add(&imageElement);
+                waitingForAnyImageToLoad = true;
+            }
+        }
+    }
+
+    if (!waitingForAnyImageToLoad)
+        computeAndSendEditDragSnapshot();
+}
+
+void WebPage::didFinishLoadingImageForElement(WebCore::HTMLImageElement& element)
+{
+    if (m_pendingImageElementsForDropSnapshot.isEmpty())
+        return;
+
+    m_pendingImageElementsForDropSnapshot.remove(&element);
+
+    if (m_pendingImageElementsForDropSnapshot.isEmpty())
+        computeAndSendEditDragSnapshot();
+}
+
+void WebPage::computeAndSendEditDragSnapshot()
+{
     Optional<TextIndicatorData> textIndicatorData;
-
     static auto defaultTextIndicatorOptionsForEditDrag = TextIndicatorOptionIncludeSnapshotOfAllVisibleContentWithoutSelection | TextIndicatorOptionExpandClipBeyondVisibleRect | TextIndicatorOptionPaintAllContent | TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionPaintBackgrounds | TextIndicatorOptionComputeEstimatedBackgroundColor| TextIndicatorOptionUseSelectionRectForSizing | TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
     auto& frame = m_page->focusController().focusedOrMainFrame();
     if (auto range = frame.selection().selection().toNormalizedRange()) {
-        if (auto textIndicator = TextIndicator::createWithRange(*range, defaultTextIndicatorOptionsForEditDrag, TextIndicatorPresentationTransition::None, FloatSize()))
+        if (auto textIndicator = TextIndicator::createWithRange(*range, defaultTextIndicatorOptionsForEditDrag, TextIndicatorPresentationTransition::None, { }))
             textIndicatorData = textIndicator->data();
     }
+    send(Messages::WebPageProxy::DidReceiveEditDragSnapshot(WTFMove(textIndicatorData)));
+}
 
-    send(Messages::WebPageProxy::DidConcludeEditDrag(WTFMove(textIndicatorData)));
-}
 #endif
 
 void WebPage::sendTapHighlightForNodeIfNecessary(uint64_t requestID, Node* node)

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (245777 => 245778)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1,3 +1,17 @@
+2019-05-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Dropped text, attachments, and images should animate into place
+        https://bugs.webkit.org/show_bug.cgi?id=198243
+        <rdar://problem/35205373>
+
+        Reviewed by Tim Horton.
+
+        Add a new chrome client method. See other changelogs for more detail.
+
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::didFinishLoadingImageForElement):
+
 2019-05-21  Alex Christensen  <[email protected]>
 
         Fix IOSMAC build

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h (245777 => 245778)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -31,6 +31,10 @@
 #import <WebCore/FocusDirection.h>
 #import <wtf/Forward.h>
 
+namespace WebCore {
+class HTMLImageElement;
+}
+
 @class WebView;
 
 // FIXME: This class is used as a concrete class on Mac, but on iOS this is an abstract
@@ -102,6 +106,8 @@
     WebCore::IntPoint accessibilityScreenToRootView(const WebCore::IntPoint&) const final;
     WebCore::IntRect rootViewToAccessibilityScreen(const WebCore::IntRect&) const final;
 
+    void didFinishLoadingImageForElement(WebCore::HTMLImageElement&) final;
+
     PlatformPageClient platformPageClient() const final;
     void contentsSizeChanged(WebCore::Frame&, const WebCore::IntSize&) const final;
     void intrinsicContentsSizeChanged(const WebCore::IntSize&) const final { }

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm (245777 => 245778)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -610,6 +610,10 @@
     return rootViewToScreen(r);
 }
 
+void WebChromeClient::didFinishLoadingImageForElement(HTMLImageElement&)
+{
+}
+
 PlatformPageClient WebChromeClient::platformPageClient() const
 {
     return 0;

Modified: trunk/Source/WebKitLegacy/win/ChangeLog (245777 => 245778)


--- trunk/Source/WebKitLegacy/win/ChangeLog	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/win/ChangeLog	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1,3 +1,15 @@
+2019-05-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Dropped text, attachments, and images should animate into place
+        https://bugs.webkit.org/show_bug.cgi?id=198243
+        <rdar://problem/35205373>
+
+        Reviewed by Tim Horton.
+
+        * WebCoreSupport/WebChromeClient.cpp:
+        (WebChromeClient::didFinishLoadingImageForElement):
+        * WebCoreSupport/WebChromeClient.h:
+
 2019-05-03  Daniel Bates  <[email protected]>
 
         Pass KeyboardEvent by reference in more places

Modified: trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.cpp (245777 => 245778)


--- trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.cpp	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.cpp	2019-05-26 11:31:49 UTC (rev 245778)
@@ -703,6 +703,10 @@
     return Icon::createIconForFiles(filenames);
 }
 
+void WebChromeClient::didFinishLoadingImageForElement(WebCore::HTMLImageElement&)
+{
+}
+
 void WebChromeClient::setCursor(const Cursor& cursor)
 {
     if (!cursor.platformCursor())

Modified: trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.h (245777 => 245778)


--- trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -172,6 +172,8 @@
 
     RefPtr<WebCore::Icon> createIconForFiles(const Vector<String>&) final;
 
+    void didFinishLoadingImageForElement(WebCore::HTMLImageElement&) final;
+
 private:
     COMPtr<IWebUIDelegate> uiDelegate();
 

Modified: trunk/Tools/ChangeLog (245777 => 245778)


--- trunk/Tools/ChangeLog	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Tools/ChangeLog	2019-05-26 11:31:49 UTC (rev 245778)
@@ -1,3 +1,41 @@
+2019-05-26  Wenson Hsieh  <[email protected]>
+
+        [iOS] Dropped text, attachments, and images should animate into place
+        https://bugs.webkit.org/show_bug.cgi?id=198243
+        <rdar://problem/35205373>
+
+        Reviewed by Tim Horton.
+
+        Adjusts the iOS dragging simulator, and adds a new API test. See below for more detail.
+
+        * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
+        (TestWebKitAPI::isCompletelyWhite):
+        (TestWebKitAPI::TEST):
+
+        Add a test that drags and drops an image into a contenteditable element, and then observes the resulting
+        UITargetedDragPreviews upon drop.
+
+        * TestWebKitAPI/cocoa/DragAndDropSimulator.h:
+        * TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
+        (-[DragAndDropSimulator _resetSimulatedState]):
+        (-[DragAndDropSimulator runFrom:to:additionalItemRequestLocations:]):
+        (-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):
+
+        Teach the iOS version of DragAndDropSimulator to invoke -dropInteraction:concludeDrop: on the drop interaction
+        delegate when the drop finishes. This additionally uses _doAfterReceivingEditDragSnapshotForTesting: to defer
+        the end of the simulated drag and drop until after drag previews have been received during an edit drag.
+
+        (-[DragAndDropSimulator dropPreviews]):
+        (-[DragAndDropSimulator delayedDropPreviews]):
+
+        Have the drag and drop simulator remember which previews were returned by the delegate on drop, as well as which
+        previews were provided asynchronously.
+
+        (-[DragAndDropSimulator _webView:dataInteractionOperationWasHandled:forSession:itemProviders:]):
+        * TestWebKitAPI/ios/UIKitSPI.h:
+
+        Stage the new private drop interacton delegate method.
+
 2019-05-25  Simon Fraser  <[email protected]>
 
         MobileMiniBrowser: Add iPad support, and allow insecure loads

Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm (245777 => 245778)


--- trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -2107,6 +2107,44 @@
     TestWebKitAPI::Util::run(&done);
 }
 
+static BOOL isCompletelyWhite(UIImage *image)
+{
+    auto data = ""
+    auto* dataPtr = CFDataGetBytePtr(data.get());
+    int imageWidth = image.size.width;
+    for (int row = 0; row < image.size.height; ++row) {
+        for (int column = 0; column < imageWidth; ++column) {
+            int pixelOffset = ((imageWidth * row) + column) * 4;
+            if (dataPtr[pixelOffset] != 0xFF || dataPtr[pixelOffset + 1] != 0xFF || dataPtr[pixelOffset + 2] != 0xFF)
+                return NO;
+        }
+    }
+    return YES;
+}
+
+TEST(DragAndDropTests, DropPreviewForImageInEditableArea)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
+
+    // Ensure that the resulting snapshot on drop contains only the dragged image.
+    [webView stringByEvaluatingJavaScript:@"editor.style.border = 'none'; editor.style.outline = 'none'"];
+
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 300)];
+
+    NSArray *dropPreviews = [simulator dropPreviews];
+    NSArray *delayedDropPreviews = [simulator delayedDropPreviews];
+    EXPECT_EQ(1U, dropPreviews.count);
+    EXPECT_EQ(1U, delayedDropPreviews.count);
+    EXPECT_EQ(UITargetedDragPreview.class, [dropPreviews.firstObject class]);
+    EXPECT_EQ(UITargetedDragPreview.class, [delayedDropPreviews.firstObject class]);
+
+    UITargetedDragPreview *finalPreview = (UITargetedDragPreview *)delayedDropPreviews.firstObject;
+    EXPECT_EQ(UIImageView.class, finalPreview.view.class);
+    EXPECT_FALSE(isCompletelyWhite([(UIImageView *)finalPreview.view image]));
+}
+
 } // namespace TestWebKitAPI
 
 #endif // ENABLE(DRAG_SUPPORT) && PLATFORM(IOS_FAMILY)

Modified: trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h (245777 => 245778)


--- trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -111,6 +111,8 @@
 @property (nonatomic, readonly) NSArray *finalSelectionRects;
 @property (nonatomic, readonly) CGRect lastKnownDragCaretRect;
 @property (nonatomic, readonly) NSArray<UITargetedDragPreview *> *liftPreviews;
+@property (nonatomic, readonly) NSArray *dropPreviews;
+@property (nonatomic, readonly) NSArray *delayedDropPreviews;
 @property (nonatomic, readonly) BOOL suppressedSelectionCommandsDuringDrop;
 
 #endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm (245777 => 245778)


--- trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm	2019-05-26 11:31:49 UTC (rev 245778)
@@ -34,6 +34,7 @@
 
 #import <UIKit/UIDragInteraction.h>
 #import <UIKit/UIDragItem.h>
+#import <UIKit/UIDropInteraction.h>
 #import <UIKit/UIInteraction.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/_WKFocusedElementInfo.h>
@@ -310,6 +311,8 @@
     RetainPtr<NSMutableDictionary<NSNumber *, NSValue *>>_remainingAdditionalItemRequestLocationsByProgress;
     RetainPtr<NSMutableArray<NSValue *>>_queuedAdditionalItemRequestLocations;
     RetainPtr<NSMutableArray<UITargetedDragPreview *>> _liftPreviews;
+    RetainPtr<NSMutableArray> _dropPreviews;
+    RetainPtr<NSMutableArray> _delayedDropPreviews;
 
     RetainPtr<NSMutableArray<_WKAttachment *>> _insertedAttachments;
     RetainPtr<NSMutableArray<_WKAttachment *>> _removedAttachments;
@@ -317,6 +320,7 @@
     bool _hasStartedInputSession;
     double _currentProgress;
     bool _isDoneWithCurrentRun;
+    bool _isDoneWaitingForDelayedDropPreviews;
     DragAndDropPhase _phase;
 
     BOOL _suppressedSelectionCommandsDuringDrop;
@@ -373,6 +377,7 @@
     _phase = DragAndDropPhaseBeginning;
     _currentProgress = 0;
     _isDoneWithCurrentRun = false;
+    _isDoneWaitingForDelayedDropPreviews = true;
     _observedEventNames = adoptNS([[NSMutableArray alloc] init]);
     _insertedAttachments = adoptNS([[NSMutableArray alloc] init]);
     _removedAttachments = adoptNS([[NSMutableArray alloc] init]);
@@ -384,6 +389,8 @@
     _remainingAdditionalItemRequestLocationsByProgress = nil;
     _queuedAdditionalItemRequestLocations = adoptNS([[NSMutableArray alloc] init]);
     _liftPreviews = adoptNS([[NSMutableArray alloc] init]);
+    _dropPreviews = adoptNS([[NSMutableArray alloc] init]);
+    _delayedDropPreviews = adoptNS([[NSMutableArray alloc] init]);
     _hasStartedInputSession = false;
 }
 
@@ -454,6 +461,7 @@
     }
 
     Util::run(&_isDoneWithCurrentRun);
+    Util::run(&_isDoneWaitingForDelayedDropPreviews);
     [_webView clearMessageHandlers:dragAndDropEventNames()];
     _finalSelectionRects = [_webView selectionRectsAfterPresentationUpdate];
 
@@ -470,11 +478,30 @@
     _lastKnownDragCaretRect = [_webView _dragCaretRect];
     auto operation = [_lastKnownDropProposal operation];
     if (operation != UIDropOperationCancel && operation != UIDropOperationForbidden) {
+        NSInteger dropPreviewIndex = 0;
+        __block NSUInteger numberOfPendingPreviews = [_dropSession items].count;
+        _isDoneWaitingForDelayedDropPreviews = !numberOfPendingPreviews;
+        for (UIDragItem *item in [_dropSession items]) {
+            auto defaultPreview = adoptNS([[UITargetedDragPreview alloc] initWithView:_webView.get()]);
+            id <UIDropInteractionDelegate_Staging_31075005> delegate = (id <UIDropInteractionDelegate_Staging_31075005>)[_webView dropInteractionDelegate];
+            UIDropInteraction *interaction = [_webView dropInteraction];
+            [_dropPreviews addObject:[delegate dropInteraction:interaction previewForDroppingItem:item withDefault:defaultPreview.get()] ?: NSNull.null];
+            [_delayedDropPreviews addObject:NSNull.null];
+            [delegate _dropInteraction:interaction delayedPreviewProviderForDroppingItem:item previewProvider:^(UITargetedDragPreview *preview) {
+                if (preview)
+                    [_delayedDropPreviews setObject:preview atIndexedSubscript:dropPreviewIndex];
+
+                if (!--numberOfPendingPreviews)
+                    _isDoneWaitingForDelayedDropPreviews = true;
+            }];
+            ++dropPreviewIndex;
+        }
         [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] performDrop:_dropSession.get()];
         _phase = DragAndDropPhasePerformingDrop;
     } else {
-        _isDoneWithCurrentRun = YES;
+        _isDoneWithCurrentRun = true;
         _phase = DragAndDropPhaseCancelled;
+        [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] concludeDrop:_dropSession.get()];
     }
 
     [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidEnd:_dropSession.get()];
@@ -644,6 +671,16 @@
     return _liftPreviews.get();
 }
 
+- (NSArray<UITargetedDragPreview *> *)dropPreviews
+{
+    return _dropPreviews.get();
+}
+
+- (NSArray<UITargetedDragPreview *> *)delayedDropPreviews
+{
+    return _delayedDropPreviews.get();
+}
+
 - (CGRect)lastKnownDragCaretRect
 {
     return _lastKnownDragCaretRect;
@@ -729,10 +766,14 @@
 - (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray<NSItemProvider *> *)itemProviders
 {
     _suppressedSelectionCommandsDuringDrop = [_webView textInputContentView]._shouldSuppressSelectionCommands;
-    _isDoneWithCurrentRun = true;
 
     if (self.dropCompletionBlock)
         self.dropCompletionBlock(handled, itemProviders);
+
+    [_webView _doAfterReceivingEditDragSnapshotForTesting:^{
+        [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] concludeDrop:_dropSession.get()];
+        _isDoneWithCurrentRun = true;
+    }];
 }
 
 - (UIDropProposal *)_webView:(WKWebView *)webView willUpdateDropProposalToProposal:(UIDropProposal *)proposal forSession:(id <UIDropSession>)session

Modified: trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h (245777 => 245778)


--- trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h	2019-05-25 23:14:57 UTC (rev 245777)
+++ trunk/Tools/TestWebKitAPI/ios/UIKitSPI.h	2019-05-26 11:31:49 UTC (rev 245778)
@@ -183,4 +183,12 @@
 - (void)setNextPreviousItemsVisible:(BOOL)visible;
 @end
 
+#if PLATFORM(IOS)
+
+@protocol UIDropInteractionDelegate_Staging_31075005 <UIDropInteractionDelegate>
+- (void)_dropInteraction:(UIDropInteraction *)interaction delayedPreviewProviderForDroppingItem:(UIDragItem *)item previewProvider:(void(^)(UITargetedDragPreview *preview))previewProvider;
+@end
+
+#endif // PLATFORM(IOS)
+
 #endif // PLATFORM(IOS_FAMILY)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to