[Attachment Support] Support dragging attachment elements out as files on iOS
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jan 2018 15:41:39 +0000 (15:41 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Jan 2018 15:41:39 +0000 (15:41 +0000)
commit3519edbd1cc2dc317c966104fd3cd8f5dc30e20d
treee1def51357fd2024cd8af7109e9d739119fd3836
parentd7d8384bfcd8a47a87078d5377c56ad37829136e
[Attachment Support] Support dragging attachment elements out as files on iOS
https://bugs.webkit.org/show_bug.cgi?id=181199
<rdar://problem/36299316>

Reviewed by Tim Horton, Andy Estes and Joseph Pecoraro.

Source/WebCore:

Adds support for dragging "files" (i.e. creating item providers with preferred attachment presentation styles)
from attachment elements on iOS for Mail. See below for more detail.

Tests:  WKAttachmentTestsIOS.DragAttachmentInsertedAsData
        WKAttachmentTestsIOS.DragAttachmentInsertedAsFile

* page/DragController.cpp:
(WebCore::DragController::platformContentTypeForBlobType const):
(WebCore::DragController::dragAttachmentElement):
* page/DragController.h:
* page/mac/DragControllerMac.mm:
(WebCore::DragController::platformContentTypeForBlobType const):

Add a private method to convert the type of a promised blob to a platform type. For Cocoa platforms, this
converts the blob type (either a UTI or a MIME type) to a UTI for the platform to consume.

* platform/ios/WebItemProviderPasteboard.h:
* platform/ios/WebItemProviderPasteboard.mm:

Refactor WebItemProviderRegistrationInfo. WebItemProviderRegistrationInfo currently encapsulates a single item
provider registration call, and contains either a type identifier and data buffer, or an NSItemProviderWriting-
conformant object. To register an item provider using a WebItemProviderRegistrationInfo, the item provider
pasteboard currently checks to see whether the info contains an object or a type and data.

This patch removes WebItemProviderRegistrationInfo and replaces it with WebItemProviderDataRegistrar. Objects
that implement this protocol know how to take an NSItemProvider and register data to it. So far, there are
three implementations below.

(-[WebItemProviderDataRegistrar initWithData:type:]):
(-[WebItemProviderDataRegistrar typeIdentifier]):
(-[WebItemProviderDataRegistrar data]):
(-[WebItemProviderDataRegistrar typeIdentifierForClient]):
(-[WebItemProviderDataRegistrar dataForClient]):
(-[WebItemProviderDataRegistrar registerItemProvider:]):
(-[WebItemProviderDataRegistrar description]):

A data registrar takes a UTI and data buffer, and registers the UTI to the data. This replaces a
WebItemProviderRegistrationInfo with both a type and data, but no representing object.

(-[WebItemProviderWritableObjectRegistrar initWithObject:]):
(-[WebItemProviderWritableObjectRegistrar representingObjectForClient]):
(-[WebItemProviderWritableObjectRegistrar registerItemProvider:]):
(-[WebItemProviderWritableObjectRegistrar description]):

The writable object registrar writes an NSItemProviderWriting-conformant object to an item provider. This
replaces a WebItemProviderRegistrationInfo with only a representing object.

(-[WebItemProviderPromisedFileRegistrar initWithType:callback:]):
(-[WebItemProviderPromisedFileRegistrar registerItemProvider:]):
(-[WebItemProviderPromisedFileRegistrar description]):
(-[WebItemProviderRegistrationInfoList addData:forType:]):
(-[WebItemProviderRegistrationInfoList addRepresentingObject:]):
(-[WebItemProviderRegistrationInfoList addPromisedType:fileCallback:]):

Helper methods to add new registrars to a registration info list.

(-[WebItemProviderRegistrationInfoList itemAtIndex:]):
(-[WebItemProviderRegistrationInfoList enumerateItems:]):
(-[WebItemProviderRegistrationInfoList itemProvider]):
(-[WebItemProviderRegistrationInfoList description]):
(-[WebItemProviderRegistrationInfo initWithRepresentingObject:typeIdentifier:data:]): Deleted.
(-[WebItemProviderRegistrationInfo representingObject]): Deleted.
(-[WebItemProviderRegistrationInfo typeIdentifier]): Deleted.

Source/WebKit:

Implement support for registering and beginning a drag with promised blob info. See below for more detail.

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKDragSessionContext addTemporaryDirectory:]):
(-[WKDragSessionContext cleanUpTemporaryDirectories]):

Introduce WKDragSessionContext, which represents the localContext of a UIDragSession initiated in WebKit. The
blob promise dragging codepath uses this to register temporary directories when saving blob data to a location
on disk; when all data transfers are finished, or if the drag interaction is being reset, we then use
-cleanUpTemporaryDirectories to remove each temporary directory.

(existingLocalDragSessionContext):
(ensureLocalDragSessionContext):

Helper methods to set the UIDragSession's localContext to a WKDragSessionContext and query for any existing
context.

(-[WKContentView cleanupInteraction]):

Before the content view's UIDragInteraction goes away, clean up any temporary directories added to the
UIDragSession.

(-[WKContentView _prepareToDragPromisedBlob:]):

When dragging with a promised blob, register a new item provider on the pasteboard representing the blob data,
along with any additional metadata associated with the blob. For the promise callback, call out to the network
process to write the blob data to a temporary path; when done, call the NSItemProvider's completion handler with
the temporary blob data location.

(-[WKContentView _itemsForBeginningOrAddingToSessionWithRegistrationList:stagedDragSource:]):
(-[WKContentView dragInteraction:sessionDidTransferItems:]):

Use this delegate hook as an opportunity to remove any temporary directories created when promised blob data is
requested upon drop. Since we know the drag session that has finished transferring data, we simply ask its local
context (a WKDragSessionContext) to remove any temporary filepaths it has created.

Tools:

Add support in the drag and drop simulator for testing blob-backed attachment element dragging, and also add new
attachment API tests.

* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(-[NSItemProvider expectType:withData:]):
(TestWebKitAPI::TEST):

Add two new WKAttachmentTests to exercise dragging data- and file-backed blobs via attachment elements. These
tests first insert attachments via drop or WKWebView SPI, and then drag these attachments out and use the
-expectType:withData: helper to inspect the item providers created from the drag source.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/ios/DataInteractionSimulator.h:
* TestWebKitAPI/ios/DataInteractionSimulator.mm:
(-[MockDragSession localContext]):
(-[MockDragSession setLocalContext:]):
(-[DataInteractionSimulator _resetSimulatedState]):
(-[DataInteractionSimulator simulateAllTouchesCanceled:]):
(-[DataInteractionSimulator _concludeDataInteractionAndPerformOperationIfNecessary]):
(-[DataInteractionSimulator _advanceProgress]):
(-[DataInteractionSimulator endDataTransfer]):

Make some tweaks to the iOS drag and drop simulator. In particular, this patch (1) adds a new hook to tell
WebKit that data transfers have been completed, (2) fixes incorrect drop proposal handling when returning
UIDropOperationForbidden by replacing _shouldPerformOperation with a UIDropProposal, and (3) teach the
MockDragSession to hold on to a localContext.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226779 268f45cc-cd09-0410-ab3c-d52691b4dbfc
13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/DragController.cpp
Source/WebCore/page/DragController.h
Source/WebCore/page/mac/DragControllerMac.mm
Source/WebCore/platform/ios/WebItemProviderPasteboard.h
Source/WebCore/platform/ios/WebItemProviderPasteboard.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm