[Attachment Support] Augment _WKAttachment SPI to handle NSFileWrappers in addition...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Aug 2018 21:10:34 +0000 (21:10 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Aug 2018 21:10:34 +0000 (21:10 +0000)
commit267924c8849e1f3806c01b20e815b454bde3db1a
treea46f4acdc6f1c413405e284229d88a1154c10a52
parent346c9503be7a442f356c4ed870099ff7c6076ec5
[Attachment Support] Augment _WKAttachment SPI to handle NSFileWrappers in addition to NSData
https://bugs.webkit.org/show_bug.cgi?id=188496
<rdar://problem/43216836>

Reviewed by Tim Horton.

Source/WebCore:

Refactors logic around HTMLAttachmentElement and pasteboard reading helpers, in support of moving the data
backing for attachment elements to the client layer, instead of keeping it in the attachment element's File.
Augmented existing API tests in WKAttachmentTests, and also added a new API test (see Tools for more detail).

* WebCore.xcodeproj/project.pbxproj:
* dom/Document.cpp:
(WebCore::Document::didInsertAttachmentElement):

Notify the client layer when a newly inserted attachment element's identifier has been updated to avoid
colliding with the identifier of an existing attachment element. This can happen if, for instance, one or more
attachments are copied and pasted within the same document.

* editing/Editor.cpp:
(WebCore::Editor::registerAttachmentIdentifier):
(WebCore::Editor::cloneAttachmentData):

Add new helper functions to notify the client when the attachment identifier to data mapping needs to be
updated. This can happen in three ways: (1) an attachment is created with raw data, or (2) an attachment is
created with a file path, or (3) the unique identifier for an attachment element has been reassigned. These
correspond to the two versions of `registerAttachmentIdentifier`, and `cloneAttachmentData`, respectively.

(WebCore::EditorClient::supportsClientSideAttachmentData const):

Add a new EditorClient hook to determine whether client-side attachment data management is supported. Currently,
this only returns true for WebKit2. If this flag is set to true, we register attachment identifiers and don't
create a new File object for the attachment element; otherwise, fall back to creating and setting a File for the
new attachment element.

(WebCore::Editor::insertAttachment):
(WebCore::Editor::insertAttachmentFromFile): Deleted.

Adjust logic when inserting an attachment; we now only need to update the attributes of the attachment element
with metadata from the client layer.

* editing/Editor.h:
* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::supportsClientSideAttachmentData):
(WebCore::createFragmentForImageAttachment):

Notify the client when creating an attachment element from image data on the pasteboard.

(WebCore::replaceRichContentWithAttachments):

Refactor this helper function to no longer connect attachment elements to File objects created from
subresources. Instead, just update each attachment element's attributes using information about the subresource,
and then notify the client about the new attachment data and attachment identifier.

(WebCore::createFragmentAndAddResources):
(WebCore::sanitizeMarkupWithArchive):

Plumb the current WebContentReader's Frame& to each of these helpers, so that it can call out to the client.

(WebCore::WebContentReader::readWebArchive):
(WebCore::WebContentMarkupReader::readWebArchive):
(WebCore::WebContentReader::readImage):
(WebCore::WebContentReader::readFilePaths):

Notify the client when creating an attachment from the path of a dropped file.

* html/AttachmentTypes.h:

Remove AttachmentInfo. This is no longer necessary because we don't need to request attachment data from the web
process anymore.

* html/HTMLAttachmentElement.cpp:
(WebCore::HTMLAttachmentElement::ensureUniqueIdentifier):

Add a helper function on the attachment element to create and return a unique identifier if needed.

(WebCore::HTMLAttachmentElement::updateAttributes):

Add a helper method to update the displayed element attributes (type, title and subtitle) or an attachment.

(WebCore::AttachmentDataReader::create): Deleted.
(WebCore::AttachmentDataReader::AttachmentDataReader): Deleted.

Remove AttachmentDataReader. This helper class was only used to load attachment data when requesting attachment
information in the client, but this is now obviated by moving attachment data to the client layer.

(WebCore::HTMLAttachmentElement::updateFileWithData): Deleted.
(WebCore::HTMLAttachmentElement::requestInfo): Deleted.
(WebCore::HTMLAttachmentElement::destroyReader): Deleted.
(WebCore::AttachmentDataReader::~AttachmentDataReader): Deleted.
(WebCore::AttachmentDataReader::didFinishLoading): Deleted.
(WebCore::AttachmentDataReader::didFail): Deleted.
(WebCore::AttachmentDataReader::invokeCallbackAndFinishReading): Deleted.
* html/HTMLAttachmentElement.h:
* page/DragClient.h:
* page/DragController.cpp:
(WebCore::DragController::startDrag):
(WebCore::DragController::doSystemDrag):
(WebCore::DragController::promisedAttachmentInfo):

Allow dragging an attachment (even if it does not have a file) as long as it has a unique identifier and a
content type.

(WebCore::DragController::promisedBlobInfo): Deleted.
* page/DragController.h:
* page/EditorClient.h:
(WebCore::EditorClient::registerAttachmentIdentifier):
(WebCore::EditorClient::cloneAttachmentData):
* platform/DragItem.h:
(WebCore::DragItem::encode const):
(WebCore::DragItem::decode):
* platform/PromisedAttachmentInfo.h: Renamed from Source/WebCore/platform/PromisedBlobInfo.h.

Add an attachment identifier to PromisedBlobInfo. Additionally, rename PromisedBlobInfo to
PromisedAttachmentInfo, since it is currently exclusively used to attachment element data to the pasteboard.
In the future, this could be renamed to something more general (e.g. PromisedPasteboardData), should we use this
mechanism to write data from other sources to the pasteboard.

(WebCore::PromisedAttachmentInfo::operator bool const):

Source/WebKit:

Adjusts WebKit's attachment editing SPI with the following modifications:
•   Deprecate `-_insertAttachmentWithFilename:contentType:data:options:completion:` in favor of
    `-_insertAttachmentWithFileWrapper:contentType:options:completion:`.
•   Deprecate `-requestInfo:` and in favor of just `-info`.
•   Add a `-fileWrapper` property to `_WKAttachmentInfo` that returns an `NSFileWrapper`.
•   Remove some SPI methods that would otherwise be deprecated, but are not even necessary, since they're no
    longer even used by Mail.

To make this possible, we refactor where and how attachment data is tracked. Currently, the data is stored in
the network process, and made accessible to the web process via blob URLs stored in the File object in the
attachment element. As such, requests from the UI process for attachment data would first be routed through the
web process to network process and back.

Instead, we now keep the relevant attachment data (in the form of NSFileWrapper on Cocoa platforms) in the UI
process, on API::Attachment. We additionally keep a map of attachment identifiers to API::Attachments, which
allows us to propagate the same _WKAttachment wrapper object to the SPI client for each uniquely identified
attachment element. This also has the benefit of allowing us to remove the asynchronous version of `-requestInfo:`
and replace it with just an `info` property.

Changes are covered by new and existing API tests.

* PlatformMac.cmake:

Remove APIAttachment.cpp, now that APIAttachment.cpp is listed in Sources.txt.

* Scripts/webkit/messages.py:
* Shared/Cocoa/APIObject.mm:
(API::Object::newObject):

Guard _WKAttachment creation with ENABLE_ATTACHMENT_ELEMENT.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<PromisedAttachmentInfo>::encode):
(IPC::ArgumentCoder<PromisedAttachmentInfo>::decode):
(IPC::ArgumentCoder<PromisedBlobInfo>::encode): Deleted.
(IPC::ArgumentCoder<PromisedBlobInfo>::decode): Deleted.
(IPC::ArgumentCoder<AttachmentInfo>::encode): Deleted.
(IPC::ArgumentCoder<AttachmentInfo>::decode): Deleted.
* Shared/WebCoreArgumentCoders.h:

Continue removing encoding support for WebCore::AttachmentInfo. Additionally, rename PromisedBlobInfo to
PromisedAttachmentInfo.

* Sources.txt:
* SourcesCocoa.txt:

Move APIAttachment.cpp from the SourcesCocoa.txt to the platform-agnostic Sources.txt.

* UIProcess/API/APIAttachment.cpp:
(API::Attachment::updateAttributes):

Rename setDataAndContentType to just updateAttributes; instead of sending data, only send the information needed
to update the presentational attributes of the attachment element.

(API::Attachment::requestInfo): Deleted.

Just call the completion handler with the result of `self.info`.

(API::Attachment::setDataAndContentType): Deleted.
* UIProcess/API/APIAttachment.h:

Add additional attributes: a content type, a file path, and (on Cocoa platforms) an NSFileWrapper.

* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:

Remove -_webView:didInsertAttachment:, since this is unused by any client currently, and is superceded by
-_webView:didInsertAttachment:withSource:.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView _didInsertAttachment:withSource:]):
(-[WKWebView _didRemoveAttachment:]):

Look up the API::Attachment corresponding to the identifier, and send its wrapper object to the client.

(-[WKWebView _insertAttachmentWithFilename:contentType:data:options:completion:]):
(-[WKWebView _insertAttachmentWithFileWrapper:contentType:options:completion:]):

Add a way to insert an attachment using NSFileWrapper, and reimplement _insertAttachmentWithFilename: using it.

* UIProcess/API/Cocoa/WKWebViewPrivate.h:
* UIProcess/API/Cocoa/_WKAttachment.h:
* UIProcess/API/Cocoa/_WKAttachment.mm:
(-[_WKAttachmentInfo initWithFileWrapper:filePath:contentType:]):
(-[_WKAttachmentInfo data]):
(-[_WKAttachmentInfo name]):
(isDeclaredOrDynamicTypeIdentifier):
(-[_WKAttachmentInfo _typeIdentifierFromPathExtension]):
(-[_WKAttachmentInfo contentType]):
(-[_WKAttachmentInfo mimeType]):
(-[_WKAttachmentInfo utiType]):
(-[_WKAttachmentInfo fileWrapper]):
(-[_WKAttachment info]):
(-[_WKAttachment requestInfo:]):

Add a property on _WKAttachment to retrieve a _WKAttachmentInfo (a snapshot of the current state of the
attachment, along with the NSFileWrapper). Reimplement requestInfo using this property.

(-[_WKAttachment setFileWrapper:contentType:completion:]):
(-[_WKAttachment setData:newContentType:newFilename:completion:]):

Reimplemented by calling -setFileWrapper:contentType:completion: with an NSFileWrapper created using the given
data. Additionally, create and associate the unique identifier with an API::Attachment right away.

(-[_WKAttachment uniqueIdentifier]):
(-[_WKAttachment description]):
(-[_WKAttachmentInfo initWithInfo:]): Deleted.
(-[_WKAttachmentInfo fileLoadingError]): Deleted.
(-[_WKAttachment isEqual:]): Deleted.
(-[_WKAttachment hash]): Deleted.

There's no longer any point to implementing these methods, since the SPI client is now guaranteed a unique
mapping of _WKAttachments to attachment elements in the document.

* UIProcess/Cocoa/PageClientImplCocoa.mm:
(WebKit::PageClientImplCocoa::didInsertAttachment):
* UIProcess/Cocoa/WebPageProxyCocoa.mm:
(WebKit::WebPageProxy::platformRegisterAttachment):
(WebKit::WebPageProxy::platformCloneAttachment):

Extend the behavior of registering new attachment data on Cocoa platforms by additionally creating and setting
NSFileWrappers on the API::Attachment.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::resetStateAfterProcessExited):

Clear out the map of attachment identifiers to API::Attachments when the web content process is terminated.

(WebKit::WebPageProxy::attachmentForIdentifier const):

Helper function to look up an API::Attachment for the given attachment identifier. Returns null if the
attachment is not found, or the attachment identifier is invalid.

(WebKit::WebPageProxy::insertAttachment):
(WebKit::WebPageProxy::updateAttachmentAttributes):
(WebKit::WebPageProxy::registerAttachmentIdentifierFromData):
(WebKit::WebPageProxy::registerAttachmentIdentifierFromFilePath):
(WebKit::WebPageProxy::cloneAttachmentData):
(WebKit::WebPageProxy::platformRegisterAttachment):
(WebKit::WebPageProxy::platformCloneAttachment):
(WebKit::WebPageProxy::didInsertAttachment):

Create an entry in the attachment identifier to API::Attachment map when an attachment is inserted, if one does
not already exist. An attachment mapping would not exist only in the case where an attachment element was
created via bindings; in this case, the client wouldn't have access to an NSFileWrapper containing the contents
of the file; in the future, this can be improved by adding a mechanism to register an attachment element with
this data, but for now, this is unnecessary for Mail's purposes.

(WebKit::WebPageProxy::didRemoveAttachment):
(WebKit::WebPageProxy::ensureAttachment):

Ensures an attachment identifier to API::Attachment mapping.

(WebKit::WebPageProxy::attachmentInfoCallback): Deleted.
(WebKit::WebPageProxy::requestAttachmentInfo): Deleted.
(WebKit::WebPageProxy::setAttachmentDataAndContentType): Deleted.
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView _startDrag:item:]):
(-[WKContentView _prepareToDragPromisedAttachment:]):
(-[WKContentView _prepareToDragPromisedBlob:]): Deleted.

Reimplement the way promised attachment data is delivered to the destination when an attachment element is
dragged. Instead of relying on the blob URL of the File on the attachment element, first try to find an API
Attachment object corresponding to the unique identifier of the dragged attachment, and use its NSFileWrapper to
deliver promised data to the destination file URL. The blob URL codepath still exists in the case where script
specifies the dragged attachment's File.

* UIProcess/mac/PageClientImplMac.h:
* UIProcess/mac/PageClientImplMac.mm:
* WebProcess/WebCoreSupport/WebEditorClient.cpp:
(WebKit::WebEditorClient::registerAttachmentIdentifier):
(WebKit::WebEditorClient::cloneAttachmentData):
* WebProcess/WebCoreSupport/WebEditorClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::insertAttachment):
(WebKit::WebPage::updateAttachmentAttributes):
(WebKit::WebPage::requestAttachmentInfo): Deleted.
(WebKit::WebPage::setAttachmentDataAndContentType): Deleted.
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

More renaming and IPC message plumbing.

Source/WebKitLegacy/win:

Adjust for changing PromisedAttachmentInfo.h to forward declare WebCore::SharedBuffer rather than include the
header directly.

* WebCoreSupport/WebDragClient.cpp:

Tools:

Adjusts existing attachment API tests. See below for more detail.

* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(-[TestWKWebView synchronouslyInsertAttachmentWithFileWrapper:contentType:]):
(-[TestWKWebView synchronouslyInsertAttachmentWithFilename:contentType:data:]):
(-[_WKAttachment synchronouslySetData:newContentType:newFilename:error:]):
(-[_WKAttachment synchronouslySetFileWrapper:newContentType:error:]):

Move off of deprecated attachment SPI, and add new helper functions to synchronously insert a new attachment or
update an existing attachment with a file wrapper.

(-[_WKAttachment expectRequestedDataToBe:]):
(TestWebKitAPI::TEST):

Add a new test to verify that file-URL-backed NSFileWrappers can be used to insert and update attachment data.
Also augment an existing test to check that an attachment element which has been copied and pasted within the
same document has a different _WKAttachment wrapper object than its duplicate, but both _WKAttachments are
backed by the same NSFileWrapper that was originally used to insert the attachment.

Additionally, add another macOS test to verify that dropping promised files in an attachment-element-enabled
editable area inserts attachment elements into the document and notifies the UI client with the inserted
attachment data.

(-[_WKAttachment synchronouslyRequestInfo:]): Deleted.
(-[_WKAttachment synchronouslyRequestData:]): Deleted.
* TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
(-[DragAndDropSimulator _webView:didInsertAttachment:withSource:]):

Move off of -_webView:didInsertAttachment:.

(-[DragAndDropSimulator _webView:didInsertAttachment:]): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235137 268f45cc-cd09-0410-ab3c-d52691b4dbfc
51 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/Document.cpp
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/Editor.h
Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
Source/WebCore/html/AttachmentTypes.h
Source/WebCore/html/HTMLAttachmentElement.cpp
Source/WebCore/html/HTMLAttachmentElement.h
Source/WebCore/page/DragClient.h
Source/WebCore/page/DragController.cpp
Source/WebCore/page/DragController.h
Source/WebCore/page/EditorClient.h
Source/WebCore/platform/DragItem.h
Source/WebCore/platform/PromisedAttachmentInfo.h [moved from Source/WebCore/platform/PromisedBlobInfo.h with 79% similarity]
Source/WebKit/ChangeLog
Source/WebKit/PlatformMac.cmake
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/Shared/Cocoa/APIObject.mm
Source/WebKit/Shared/WebCoreArgumentCoders.cpp
Source/WebKit/Shared/WebCoreArgumentCoders.h
Source/WebKit/Sources.txt
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/API/APIAttachment.cpp
Source/WebKit/UIProcess/API/APIAttachment.h
Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivate.h
Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.h
Source/WebKit/UIProcess/API/Cocoa/_WKAttachment.mm
Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm
Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/ios/PageClientImplIOS.h
Source/WebKit/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/UIProcess/mac/PageClientImplMac.h
Source/WebKit/UIProcess/mac/PageClientImplMac.mm
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebCoreSupport/WebDragClient.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm
Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm