[iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Feb 2019 00:43:40 +0000 (00:43 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 19 Feb 2019 00:43:40 +0000 (00:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194670
<rdar://problem/39066529>

Reviewed by Tim Horton.

Source/WebCore:

Adds support for pasting files on the pasteboard as attachment elements, if the attachment element runtime
switch is enabled. Currently, the only types of data that can be pasted as attachments are images, which take a
special codepath in WebContentReader::readImage.

This patch adds a readDataBuffer method that converts a given blob of data from the pasteboard into an
attachment-element-backed representation in the DOM (i.e. either an attachment element or image element that
contains an attachment element). In the case where the given pasteboard item has been explicitly marked as an
attachment (via the preferredPresentationStyle hint) and the item has at least one type representation that
conforms to "public.content", we take this codepath instead of first attempting the web content reading types
supported by default in WebKit.

See below for more detail.

Test: WKAttachmentTestsIOS.InsertPastedFilesAsAttachments

* editing/Editor.cpp:
(WebCore::Editor::clientReplacementURLForResource): Deleted.
* editing/Editor.h:
* editing/WebContentReader.h:
* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::mimeTypeFromContentType):
(WebCore::contentTypeIsSuitableForInlineImageRepresentation):
(WebCore::createFragmentAndAddResources):
(WebCore::sanitizeMarkupWithArchive):

Remove all logic for handling subresource URL replacement. See WebKit ChangeLog for more details on this.

(WebCore::WebContentReader::readImage):
(WebCore::attachmentForFilePath):
(WebCore::attachmentForData):

Add a helper that creates an attachment element for a given blob of data and content type. The logic here is
quite similar to that of attachmentForFilePath, and we should find a way to either merge them, or pull out more
of their similarities into helper functions.

(WebCore::WebContentReader::readDataBuffer):
(WebCore::replaceSubresourceURLsWithURLsFromClient): Deleted.

Remove more logic for handling subresource URL replacement. See WebKit ChangeLog for more details on this.

* loader/EmptyClients.cpp:
* page/EditorClient.h:
* platform/Pasteboard.h:
* platform/PasteboardItemInfo.h:
(WebCore::PasteboardItemInfo::contentTypeForHighestFidelityItem const):
(WebCore::PasteboardItemInfo::pathForHighestFidelityItem const):
(WebCore::PasteboardItemInfo::encode const):
(WebCore::PasteboardItemInfo::decode):

Add contentTypesByFidelity to PasteboardItemInfo, instead of requesting this information using a separate IPC
message. This means we can also remove getTypesByFidelityForItemAtIndex, and just use the item's types in
fidelity order instead.

* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/ios/AbstractPasteboard.h:
* platform/ios/PasteboardIOS.mm:
(WebCore::Pasteboard::read):

Shave off (potentially many) sync IPC messages to the UI process by pulling each call to
informationForItemAtIndex out of the inner loop when reading web content.

(WebCore::Pasteboard::readRespectingUTIFidelities):

Shave off one extraneous sync IPC message by rolling the types in fidelity order into the request for
PasteboardItemInfo, instead of being sent in a separate message.

* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::informationForItemAtIndex):

Populate contentTypesForFileUpload in the case where UIPasteboard is used (i.e. copy and paste).

(WebCore::PlatformPasteboard::getTypesByFidelityForItemAtIndex): Deleted.
* platform/ios/WebItemProviderPasteboard.h:
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard pasteboardTypesByFidelityForItemAtIndex:]): Deleted.

Source/WebKit:

Remove all IPC plumbing for getTypesByFidelityForItemAtIndex, now that the types in fidelity order have been
rolled into PasteboardItemInfo.

Additionally, remove support for subresource URL replacement. This feature was originally added with the
intention that private clients (i.e. Mail) would intercept pasted or dropped images and replace their URLs.
However, since <rdar://problem/43216836>, our strategy for this scenario has changed, such that WebKit now
handles the drop/paste, and later delivers the image data to the client via NSFileWrappers in the UI process.
At this time, there are no adopters of this SPI, and no adopters of the V2 injected bundle editing client. As
such, we can simply revert all of this to its state prior to the introduction of the replacement URL SPI, with
the exception to changes in WKBundlePageEditorClient.h, wherein there is a nonzero (but likely tiny) chance of
completely breaking binary compatability with any third parties on macOS which may have tried to adopt
subresource URL replacement.

* UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
(WebKit::WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex): Deleted.
* UIProcess/WebPasteboardProxy.h:
* UIProcess/WebPasteboardProxy.messages.in:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView canPerformActionForWebView:withSender:]):

Return YES for -paste: in the case where:
1. The pasteboard contains items that are explicitly marked as attachments.
2. The selection is richly contenteditable.
3. Attachment elements are enabled.

Among other things, this allows the callout bar on iOS to show the "Paste" action.

* WebProcess/InjectedBundle/API/APIInjectedBundleEditorClient.h:
(API::InjectedBundle::EditorClient::performTwoStepDrop):
(API::InjectedBundle::EditorClient::replacementURLForResource): Deleted.
* WebProcess/InjectedBundle/API/Cocoa/WKWebProcessPlugInEditingDelegate.h:
* WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm:
(-[WKWebProcessPlugInBrowserContextController _setEditingDelegate:]):
* WebProcess/InjectedBundle/InjectedBundlePageEditorClient.cpp:
(WebKit::InjectedBundlePageEditorClient::replacementURLForResource): Deleted.
* WebProcess/InjectedBundle/InjectedBundlePageEditorClient.h:
* WebProcess/WebCoreSupport/WebEditorClient.cpp:
(WebKit::WebEditorClient::replacementURLForResource): Deleted.
* WebProcess/WebCoreSupport/WebEditorClient.h:
* WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
(WebKit::WebPlatformStrategies::getTypesByFidelityForItemAtIndex): Deleted.
* WebProcess/WebCoreSupport/WebPlatformStrategies.h:

Source/WebKitLegacy/mac:

* WebCoreSupport/WebEditorClient.h:
* WebCoreSupport/WebEditorClient.mm:
(WebEditorClient::replacementURLForResource): Deleted.
* WebCoreSupport/WebPlatformStrategies.h:
* WebCoreSupport/WebPlatformStrategies.mm:
(WebPlatformStrategies::getTypesByFidelityForItemAtIndex): Deleted.

Source/WebKitLegacy/win:

* WebCoreSupport/WebEditorClient.cpp:
(WebEditorClient::replacementURLForResource): Deleted.
* WebCoreSupport/WebEditorClient.h:

Tools:

Remove code and tests for subresource URL replacement, and also add a new test to verify that copied data can be
pasted in an editable area as attachment elements.

* TestWebKitAPI/Tests/WebKitCocoa/BundleEditingDelegatePlugIn.mm:
(-[BundleEditingDelegatePlugIn webProcessPlugIn:didCreateBrowserContextController:]):
(-[BundleEditingDelegatePlugIn _webProcessPlugInBrowserContextController:replacementURLForResource:mimeType:]): Deleted.
* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(TestWebKitAPI::TEST):
* WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
(WTR::InjectedBundlePage::InjectedBundlePage):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@241749 268f45cc-cd09-0410-ab3c-d52691b4dbfc

42 files changed:
Source/WebCore/ChangeLog
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/Editor.h
Source/WebCore/editing/WebContentReader.h
Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
Source/WebCore/loader/EmptyClients.cpp
Source/WebCore/page/EditorClient.h
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/PasteboardItemInfo.h
Source/WebCore/platform/PasteboardStrategy.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/ios/AbstractPasteboard.h
Source/WebCore/platform/ios/PasteboardIOS.mm
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebCore/platform/ios/WebItemProviderPasteboard.h
Source/WebCore/platform/ios/WebItemProviderPasteboard.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
Source/WebKit/UIProcess/WebPasteboardProxy.h
Source/WebKit/UIProcess/WebPasteboardProxy.messages.in
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/WebProcess/InjectedBundle/API/APIInjectedBundleEditorClient.h
Source/WebKit/WebProcess/InjectedBundle/API/Cocoa/WKWebProcessPlugInEditingDelegate.h
Source/WebKit/WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm
Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageEditorClient.cpp
Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageEditorClient.h
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebEditorClient.h
Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.h
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.h
Source/WebKitLegacy/mac/WebCoreSupport/WebEditorClient.mm
Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.h
Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebCoreSupport/WebEditorClient.cpp
Source/WebKitLegacy/win/WebCoreSupport/WebEditorClient.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/BundleEditingDelegatePlugIn.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm
Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp

index 472ec06..5b161f9 100644 (file)
@@ -1,3 +1,88 @@
+2019-02-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
+        https://bugs.webkit.org/show_bug.cgi?id=194670
+        <rdar://problem/39066529>
+
+        Reviewed by Tim Horton.
+
+        Adds support for pasting files on the pasteboard as attachment elements, if the attachment element runtime
+        switch is enabled. Currently, the only types of data that can be pasted as attachments are images, which take a
+        special codepath in WebContentReader::readImage.
+
+        This patch adds a readDataBuffer method that converts a given blob of data from the pasteboard into an
+        attachment-element-backed representation in the DOM (i.e. either an attachment element or image element that
+        contains an attachment element). In the case where the given pasteboard item has been explicitly marked as an
+        attachment (via the preferredPresentationStyle hint) and the item has at least one type representation that
+        conforms to "public.content", we take this codepath instead of first attempting the web content reading types
+        supported by default in WebKit.
+
+        See below for more detail.
+
+        Test: WKAttachmentTestsIOS.InsertPastedFilesAsAttachments
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::clientReplacementURLForResource): Deleted.
+        * editing/Editor.h:
+        * editing/WebContentReader.h:
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::mimeTypeFromContentType):
+        (WebCore::contentTypeIsSuitableForInlineImageRepresentation):
+        (WebCore::createFragmentAndAddResources):
+        (WebCore::sanitizeMarkupWithArchive):
+
+        Remove all logic for handling subresource URL replacement. See WebKit ChangeLog for more details on this.
+
+        (WebCore::WebContentReader::readImage):
+        (WebCore::attachmentForFilePath):
+        (WebCore::attachmentForData):
+
+        Add a helper that creates an attachment element for a given blob of data and content type. The logic here is
+        quite similar to that of attachmentForFilePath, and we should find a way to either merge them, or pull out more
+        of their similarities into helper functions.
+
+        (WebCore::WebContentReader::readDataBuffer):
+        (WebCore::replaceSubresourceURLsWithURLsFromClient): Deleted.
+
+        Remove more logic for handling subresource URL replacement. See WebKit ChangeLog for more details on this.
+
+        * loader/EmptyClients.cpp:
+        * page/EditorClient.h:
+        * platform/Pasteboard.h:
+        * platform/PasteboardItemInfo.h:
+        (WebCore::PasteboardItemInfo::contentTypeForHighestFidelityItem const):
+        (WebCore::PasteboardItemInfo::pathForHighestFidelityItem const):
+        (WebCore::PasteboardItemInfo::encode const):
+        (WebCore::PasteboardItemInfo::decode):
+
+        Add contentTypesByFidelity to PasteboardItemInfo, instead of requesting this information using a separate IPC
+        message. This means we can also remove getTypesByFidelityForItemAtIndex, and just use the item's types in
+        fidelity order instead.
+
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/PasteboardIOS.mm:
+        (WebCore::Pasteboard::read):
+
+        Shave off (potentially many) sync IPC messages to the UI process by pulling each call to
+        informationForItemAtIndex out of the inner loop when reading web content.
+
+        (WebCore::Pasteboard::readRespectingUTIFidelities):
+
+        Shave off one extraneous sync IPC message by rolling the types in fidelity order into the request for
+        PasteboardItemInfo, instead of being sent in a separate message.
+
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::informationForItemAtIndex):
+
+        Populate contentTypesForFileUpload in the case where UIPasteboard is used (i.e. copy and paste).
+
+        (WebCore::PlatformPasteboard::getTypesByFidelityForItemAtIndex): Deleted.
+        * platform/ios/WebItemProviderPasteboard.h:
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderPasteboard pasteboardTypesByFidelityForItemAtIndex:]): Deleted.
+
 2019-02-18  Daniel Bates  <dabates@apple.com>
 
         Clean up and modernize RenderThemeIOS::paintCheckboxDecorations()
index 5abdbf8..937e744 100644 (file)
@@ -4258,14 +4258,6 @@ const Font* Editor::fontForSelection(bool& hasMultipleFonts) const
     return font;
 }
 
-String Editor::clientReplacementURLForResource(Ref<SharedBuffer>&& resourceData, const String& mimeType)
-{
-    if (auto* editorClient = client())
-        return editorClient->replacementURLForResource(WTFMove(resourceData), mimeType);
-
-    return { };
-}
-
 RefPtr<HTMLImageElement> Editor::insertEditableImage()
 {
     return InsertEditableImageCommand::insertEditableImage(document());
index 3b4a6d2..e08da32 100644 (file)
@@ -500,8 +500,6 @@ public:
 
     bool canCopyExcludingStandaloneImages() const;
 
-    String clientReplacementURLForResource(Ref<SharedBuffer>&& resourceData, const String& mimeType);
-
 #if !PLATFORM(WIN)
     WEBCORE_EXPORT void writeSelectionToPasteboard(Pasteboard&);
     WEBCORE_EXPORT void writeImageToPasteboard(Pasteboard&, Element& imageElement, const URL&, const String& title);
index c774b4a..7e78db1 100644 (file)
@@ -78,6 +78,7 @@ private:
     bool readImage(Ref<SharedBuffer>&&, const String& type) override;
     bool readURL(const URL&, const String& title) override;
     bool readVirtualContactFile(const String& filePath, const URL&, const String& urlTitle) override;
+    bool readDataBuffer(SharedBuffer&, const String& type, const String& name) override;
 #endif
     bool readPlainText(const String&) override;
 };
@@ -101,6 +102,7 @@ private:
     bool readRTF(SharedBuffer&) override;
     bool readImage(Ref<SharedBuffer>&&, const String&) override { return false; }
     bool readURL(const URL&, const String&) override { return false; }
+    bool readDataBuffer(SharedBuffer&, const String&, const String&) override { return false; }
 #endif
     bool readPlainText(const String&) override { return false; }
 };
index 254a368..9e8e265 100644 (file)
@@ -220,9 +220,14 @@ static bool shouldReplaceRichContentWithAttachments()
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
+static String mimeTypeFromContentType(const String& contentType)
+{
+    return isDeclaredUTI(contentType) ? MIMETypeFromUTI(contentType) : contentType;
+}
+
 static bool contentTypeIsSuitableForInlineImageRepresentation(const String& contentType)
 {
-    return MIMETypeRegistry::isSupportedImageMIMEType(isDeclaredUTI(contentType) ? MIMETypeFromUTI(contentType) : contentType);
+    return MIMETypeRegistry::isSupportedImageMIMEType(mimeTypeFromContentType(contentType));
 }
 
 static bool supportsClientSideAttachmentData(const Frame& frame)
@@ -370,31 +375,6 @@ static void replaceRichContentWithAttachments(Frame& frame, DocumentFragment& fr
 #endif
 }
 
-static void replaceSubresourceURLsWithURLsFromClient(DocumentFragment& fragment, const Vector<Ref<ArchiveResource>>& subresources, Vector<Ref<ArchiveResource>>& outUnreplacedResources)
-{
-    ASSERT(fragment.document().frame());
-    auto& frame = *fragment.document().frame();
-    HashMap<AtomicString, AtomicString> subresourceURLToClientURLMap;
-    for (auto& subresource : subresources) {
-        auto& originalURL = subresource->url();
-        if (!shouldReplaceSubresourceURL(originalURL)) {
-            outUnreplacedResources.append(subresource.copyRef());
-            continue;
-        }
-
-        auto replacementURL = frame.editor().clientReplacementURLForResource(subresource->data(), subresource->mimeType());
-        if (replacementURL.isEmpty()) {
-            outUnreplacedResources.append(subresource.copyRef());
-            continue;
-        }
-
-        subresourceURLToClientURLMap.set(originalURL.string(), replacementURL);
-    }
-
-    if (!subresourceURLToClientURLMap.isEmpty())
-        replaceSubresourceURLs(fragment, WTFMove(subresourceURLToClientURLMap));
-}
-
 RefPtr<DocumentFragment> createFragmentAndAddResources(Frame& frame, NSAttributedString *string)
 {
     if (!frame.page() || !frame.document())
@@ -417,16 +397,13 @@ RefPtr<DocumentFragment> createFragmentAndAddResources(Frame& frame, NSAttribute
         return WTFMove(fragmentAndResources.fragment);
     }
 
-    Vector<Ref<ArchiveResource>> unreplacedResources;
-    replaceSubresourceURLsWithURLsFromClient(*fragmentAndResources.fragment, fragmentAndResources.resources, unreplacedResources);
-
     if (shouldReplaceRichContentWithAttachments()) {
-        replaceRichContentWithAttachments(frame, *fragmentAndResources.fragment, unreplacedResources);
+        replaceRichContentWithAttachments(frame, *fragmentAndResources.fragment, fragmentAndResources.resources);
         return WTFMove(fragmentAndResources.fragment);
     }
 
     HashMap<AtomicString, AtomicString> blobURLMap;
-    for (const Ref<ArchiveResource>& subresource : unreplacedResources) {
+    for (const Ref<ArchiveResource>& subresource : fragmentAndResources.resources) {
         auto blob = Blob::create(subresource->data(), subresource->mimeType());
         String blobURL = DOMURL::createObjectURL(document, blob);
         blobURLMap.set(subresource->url().string(), blobURL);
@@ -466,16 +443,13 @@ static String sanitizeMarkupWithArchive(Frame& frame, Document& destinationDocum
     ASSERT(stagingDocument);
     auto fragment = createFragmentFromMarkup(*stagingDocument, markupAndArchive.markup, markupAndArchive.mainResource->url(), DisallowScriptingAndPluginContent);
 
-    Vector<Ref<ArchiveResource>> unreplacedResources;
-    replaceSubresourceURLsWithURLsFromClient(fragment, markupAndArchive.archive->subresources(), unreplacedResources);
-
     if (shouldReplaceRichContentWithAttachments()) {
-        replaceRichContentWithAttachments(frame, fragment, unreplacedResources);
+        replaceRichContentWithAttachments(frame, fragment, markupAndArchive.archive->subresources());
         return sanitizedMarkupForFragmentInDocument(WTFMove(fragment), *stagingDocument, msoListQuirks, markupAndArchive.markup);
     }
 
     HashMap<AtomicString, AtomicString> blobURLMap;
-    for (const Ref<ArchiveResource>& subresource : unreplacedResources) {
+    for (const Ref<ArchiveResource>& subresource : markupAndArchive.archive->subresources()) {
         auto& subresourceURL = subresource->url();
         if (!shouldReplaceSubresourceURL(subresourceURL))
             continue;
@@ -700,13 +674,6 @@ bool WebContentReader::readImage(Ref<SharedBuffer>&& buffer, const String& type)
 {
     ASSERT(frame.document());
     auto& document = *frame.document();
-
-    auto replacementURL = frame.editor().clientReplacementURLForResource(buffer.copyRef(), isDeclaredUTI(type) ? MIMETypeFromUTI(type) : type);
-    if (!replacementURL.isEmpty()) {
-        addFragment(createFragmentForImageAndURL(document, replacementURL));
-        return true;
-    }
-
     if (shouldReplaceRichContentWithAttachments())
         addFragment(createFragmentForImageAttachment(frame, document, WTFMove(buffer), type));
     else
@@ -723,7 +690,7 @@ static Ref<HTMLElement> attachmentForFilePath(Frame& frame, const String& path)
     auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
     if (!supportsClientSideAttachmentData(frame)) {
         attachment->setFile(File::create(path), HTMLAttachmentElement::UpdateDisplayAttributes::Yes);
-        return attachment.get();
+        return attachment;
     }
 
     String contentType;
@@ -745,11 +712,45 @@ static Ref<HTMLElement> attachmentForFilePath(Frame& frame, const String& path)
         auto image = HTMLImageElement::create(document);
         image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(path)));
         image->setAttachmentElement(WTFMove(attachment));
-        return image.get();
+        return image;
     }
 
     attachment->updateAttributes(WTFMove(fileSizeForDisplay), contentType, FileSystem::pathGetFileName(path));
-    return attachment.get();
+    return attachment;
+}
+
+static Ref<HTMLElement> attachmentForData(Frame& frame, SharedBuffer& buffer, const String& contentType, const String& name)
+{
+    auto document = makeRef(*frame.document());
+    auto attachment = HTMLAttachmentElement::create(HTMLNames::attachmentTag, document);
+    auto mimeType = mimeTypeFromContentType(contentType);
+    auto typeForAttachmentElement = mimeType.isEmpty() ? contentType : mimeType;
+
+    // FIXME: We should instead ask CoreServices for a preferred name corresponding to the given content type.
+    static const char* defaultAttachmentName = "file";
+
+    String fileName;
+    if (name.isEmpty())
+        fileName = defaultAttachmentName;
+    else
+        fileName = name;
+
+    if (!supportsClientSideAttachmentData(frame)) {
+        attachment->setFile(File::create(Blob::create(buffer, WTFMove(typeForAttachmentElement)), fileName));
+        return attachment;
+    }
+
+    frame.editor().registerAttachmentIdentifier(attachment->ensureUniqueIdentifier(), typeForAttachmentElement, fileName, buffer);
+
+    if (contentTypeIsSuitableForInlineImageRepresentation(typeForAttachmentElement)) {
+        auto image = HTMLImageElement::create(document);
+        image->setAttributeWithoutSynchronization(HTMLNames::srcAttr, DOMURL::createObjectURL(document, File::create(Blob::create(buffer, WTFMove(typeForAttachmentElement)), WTFMove(fileName))));
+        image->setAttachmentElement(WTFMove(attachment));
+        return image;
+    }
+
+    attachment->updateAttributes({ buffer.size() }, WTFMove(typeForAttachmentElement), WTFMove(fileName));
+    return attachment;
 }
 
 #endif // ENABLE(ATTACHMENT_ELEMENT)
@@ -826,4 +827,28 @@ bool WebContentReader::readURL(const URL& url, const String& title)
     return true;
 }
 
+bool WebContentReader::readDataBuffer(SharedBuffer& buffer, const String& type, const String& name)
+{
+    if (buffer.isEmpty())
+        return false;
+
+    if (!shouldReplaceRichContentWithAttachments())
+        return false;
+
+    auto document = makeRefPtr(frame.document());
+    if (!document)
+        return false;
+
+    if (!fragment)
+        fragment = document->createDocumentFragment();
+
+#if ENABLE(ATTACHMENT_ELEMENT)
+    fragment->appendChild(attachmentForData(frame, buffer, type, name));
+#else
+    UNUSED_PARAM(type);
+    UNUSED_PARAM(name);
+#endif
+    return true;
+}
+
 }
index 6c2dbdf..a43a1bb 100644 (file)
@@ -182,7 +182,6 @@ private:
     void willWriteSelectionToPasteboard(Range*) final { }
     void didWriteSelectionToPasteboard() final { }
     void getClientPasteboardDataForRange(Range*, Vector<String>&, Vector<RefPtr<SharedBuffer>>&) final { }
-    String replacementURLForResource(Ref<SharedBuffer>&&, const String&) final { return { }; }
     void requestCandidatesForSelection(const VisibleSelection&) final { }
     void handleAcceptedCandidateWithSoftSpaces(TextCheckingResult) final { }
 
index 6e0d0be..bc6584b 100644 (file)
@@ -94,7 +94,6 @@ public:
     virtual void willWriteSelectionToPasteboard(Range*) = 0;
     virtual void didWriteSelectionToPasteboard() = 0;
     virtual void getClientPasteboardDataForRange(Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<SharedBuffer>>& pasteboardData) = 0;
-    virtual String replacementURLForResource(Ref<SharedBuffer>&& resourceData, const String& mimeType) = 0;
     virtual void requestCandidatesForSelection(const VisibleSelection&) { }
     virtual void handleAcceptedCandidateWithSoftSpaces(TextCheckingResult) { }
 
index 7d2715c..35a831d 100644 (file)
@@ -143,6 +143,7 @@ public:
     virtual bool readRTF(SharedBuffer&) = 0;
     virtual bool readImage(Ref<SharedBuffer>&&, const String& type) = 0;
     virtual bool readURL(const URL&, const String& title) = 0;
+    virtual bool readDataBuffer(SharedBuffer&, const String& type, const String& name) = 0;
 #endif
     virtual bool readPlainText(const String&) = 0;
 };
index 22a098a..92d8b0b 100644 (file)
@@ -40,6 +40,7 @@ enum class PasteboardItemPresentationStyle {
 struct PasteboardItemInfo {
     Vector<String> pathsForFileUpload;
     Vector<String> contentTypesForFileUpload;
+    Vector<String> contentTypesByFidelity;
     String suggestedFileName;
     bool isNonTextType { false };
     bool containsFileURLAndFileUploadContent { false };
@@ -55,12 +56,19 @@ struct PasteboardItemInfo {
         return pathsForFileUpload[index];
     }
 
+    String contentTypeForHighestFidelityItem() const
+    {
+        if (contentTypesForFileUpload.isEmpty())
+            return { };
+
+        return contentTypesForFileUpload.first();
+    }
+
     String pathForHighestFidelityItem() const
     {
         if (pathsForFileUpload.isEmpty())
             return { };
 
-        ASSERT(!pathsForFileUpload.first().isEmpty());
         return pathsForFileUpload.first();
     }
 
@@ -71,7 +79,7 @@ struct PasteboardItemInfo {
 template<class Encoder>
 void PasteboardItemInfo::encode(Encoder& encoder) const
 {
-    encoder << pathsForFileUpload << contentTypesForFileUpload << suggestedFileName << isNonTextType << containsFileURLAndFileUploadContent;
+    encoder << pathsForFileUpload << contentTypesForFileUpload << contentTypesByFidelity << suggestedFileName << isNonTextType << containsFileURLAndFileUploadContent;
     encoder.encodeEnum(preferredPresentationStyle);
 }
 
@@ -85,6 +93,9 @@ Optional<PasteboardItemInfo> PasteboardItemInfo::decode(Decoder& decoder)
     if (!decoder.decode(result.contentTypesForFileUpload))
         return WTF::nullopt;
 
+    if (!decoder.decode(result.contentTypesByFidelity))
+        return WTF::nullopt;
+
     if (!decoder.decode(result.suggestedFileName))
         return WTF::nullopt;
 
index 1e9b880..dc16f0f 100644 (file)
@@ -53,7 +53,6 @@ public:
     virtual Vector<PasteboardItemInfo> allPasteboardItemInfo(const String& pasteboardName) = 0;
     virtual PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) = 0;
     virtual void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) = 0;
-    virtual void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) = 0;
 #endif // PLATFORM(IOS_FAMILY)
 #if PLATFORM(COCOA)
     virtual void getTypes(Vector<String>& types, const String& pasteboardName) = 0;
index c35f08e..e033150 100644 (file)
@@ -61,7 +61,6 @@ public:
     WEBCORE_EXPORT PlatformPasteboard();
     WEBCORE_EXPORT Vector<PasteboardItemInfo> allPasteboardItemInfo();
     WEBCORE_EXPORT PasteboardItemInfo informationForItemAtIndex(int index);
-    WEBCORE_EXPORT void getTypesByFidelityForItemAtIndex(Vector<String>& types, int index);
     WEBCORE_EXPORT void updateSupportedTypeIdentifiers(const Vector<String>& types);
 #endif
     WEBCORE_EXPORT static String uniqueName();
index 8f2dd0a..ea56442 100644 (file)
@@ -54,7 +54,6 @@ NS_ASSUME_NONNULL_BEGIN
 - (nullable WebItemProviderRegistrationInfoList *)takeRegistrationList;
 #endif
 - (void)setItems:(NSArray<NSDictionary *> *)items;
-- (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index;
 @property (readonly, nonatomic) NSInteger numberOfFiles;
 @property (readonly, nonatomic) NSArray<NSURL *> *allDroppedFileURLs;
 
index 2071531..5ef3ce8 100644 (file)
@@ -285,13 +285,31 @@ void Pasteboard::read(PasteboardWebContentReader& reader, WebContentReadingPolic
     NSArray *types = supportedWebContentPasteboardTypes();
     int numberOfTypes = [types count];
 
+#if ENABLE(ATTACHMENT_ELEMENT)
+    bool canReadAttachment = policy == WebContentReadingPolicy::AnyType && RuntimeEnabledFeatures::sharedFeatures().attachmentElementEnabled();
+#else
+    bool canReadAttachment = false;
+#endif
+
     for (int i = 0; i < numberOfItems; i++) {
+        auto info = strategy.informationForItemAtIndex(i, m_pasteboardName);
+#if ENABLE(ATTACHMENT_ELEMENT)
+        if (canReadAttachment) {
+            auto typeForFileUpload = info.contentTypeForHighestFidelityItem();
+            if (!typeForFileUpload.isEmpty() && info.preferredPresentationStyle == PasteboardItemPresentationStyle::Attachment) {
+                auto buffer = strategy.readBufferFromPasteboard(i, typeForFileUpload, m_pasteboardName);
+                if (buffer && reader.readDataBuffer(*buffer, typeForFileUpload, info.suggestedFileName))
+                    continue;
+            }
+        }
+#endif
+
         for (int typeIndex = 0; typeIndex < numberOfTypes; typeIndex++) {
             NSString *type = [types objectAtIndex:typeIndex];
             if (!isTypeAllowedByReadingPolicy(type, policy))
                 continue;
 
-            auto itemResult = readPasteboardWebContentDataForType(reader, strategy, type, i, strategy.informationForItemAtIndex(i, m_pasteboardName));
+            auto itemResult = readPasteboardWebContentDataForType(reader, strategy, type, i, info);
             if (itemResult == ReaderResult::PasteboardWasChangedExternally)
                 return;
 
@@ -325,10 +343,8 @@ void Pasteboard::readRespectingUTIFidelities(PasteboardWebContentReader& reader,
 #endif
         // Try to read data from each type identifier that this pasteboard item supports, and WebKit also recognizes. Type identifiers are
         // read in order of fidelity, as specified by each pasteboard item.
-        Vector<String> typesForItemInOrderOfFidelity;
-        strategy.getTypesByFidelityForItemAtIndex(typesForItemInOrderOfFidelity, index, m_pasteboardName);
         ReaderResult result = ReaderResult::DidNotReadType;
-        for (auto& type : typesForItemInOrderOfFidelity) {
+        for (auto& type : info.contentTypesByFidelity) {
             if (!isTypeAllowedByReadingPolicy(type, policy))
                 continue;
 
index 200dbc3..aea98a7 100644 (file)
@@ -78,16 +78,6 @@ void PlatformPasteboard::getTypes(Vector<String>& types)
         types.append(pasteboardType);
 }
 
-void PlatformPasteboard::getTypesByFidelityForItemAtIndex(Vector<String>& types, int index)
-{
-    if (index >= [m_pasteboard numberOfItems] || ![m_pasteboard respondsToSelector:@selector(pasteboardTypesByFidelityForItemAtIndex:)])
-        return;
-
-    NSArray *pasteboardTypesByFidelity = [m_pasteboard pasteboardTypesByFidelityForItemAtIndex:index];
-    for (NSString *typeIdentifier in pasteboardTypesByFidelity)
-        types.append(typeIdentifier);
-}
-
 RefPtr<SharedBuffer> PlatformPasteboard::bufferForType(const String& type)
 {
     if (NSData *data = [m_pasteboard dataForPasteboardType:type])
@@ -139,6 +129,7 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
         return { };
 
     PasteboardItemInfo info;
+    NSItemProvider *itemProvider = [[m_pasteboard itemProviders] objectAtIndex:index];
     if ([m_pasteboard respondsToSelector:@selector(fileUploadURLsAtIndex:fileTypes:)]) {
         NSArray<NSString *> *fileTypes = nil;
         NSArray *urls = [m_pasteboard fileUploadURLsAtIndex:index fileTypes:&fileTypes];
@@ -149,17 +140,27 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
             info.pathsForFileUpload.uncheckedAppend(url.path);
 
         info.contentTypesForFileUpload.reserveInitialCapacity(fileTypes.count);
-        for (NSString *fileType : fileTypes)
+        for (NSString *fileType in fileTypes)
+            info.contentTypesForFileUpload.uncheckedAppend(fileType);
+    } else {
+        NSArray *fileTypes = itemProvider.web_fileUploadContentTypes;
+        info.contentTypesForFileUpload.reserveInitialCapacity(fileTypes.count);
+        info.pathsForFileUpload.reserveInitialCapacity(fileTypes.count);
+        for (NSString *fileType in fileTypes) {
             info.contentTypesForFileUpload.uncheckedAppend(fileType);
+            info.pathsForFileUpload.uncheckedAppend({ });
+        }
     }
 
-    NSItemProvider *itemProvider = [[m_pasteboard itemProviders] objectAtIndex:index];
 #if PASTEBOARD_SUPPORTS_PRESENTATION_STYLE_AND_TEAM_DATA
     info.preferredPresentationStyle = pasteboardItemPresentationStyle(itemProvider.preferredPresentationStyle);
 #endif
     info.containsFileURLAndFileUploadContent = itemProvider.web_containsFileURLAndFileUploadContent;
     info.suggestedFileName = itemProvider.suggestedName;
-    for (NSString *typeIdentifier in itemProvider.registeredTypeIdentifiers) {
+    NSArray<NSString *> *registeredTypeIdentifiers = itemProvider.registeredTypeIdentifiers;
+    info.contentTypesByFidelity.reserveInitialCapacity(registeredTypeIdentifiers.count);
+    for (NSString *typeIdentifier in registeredTypeIdentifiers) {
+        info.contentTypesByFidelity.uncheckedAppend(typeIdentifier);
         CFStringRef cfTypeIdentifier = (CFStringRef)typeIdentifier;
         if (!UTTypeIsDeclared(cfTypeIdentifier))
             continue;
@@ -177,7 +178,6 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
             continue;
 
         info.isNonTextType = true;
-        break;
     }
 
     return info;
index 29f9a71..e45d24e 100644 (file)
@@ -39,6 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 @interface NSItemProvider (WebCoreExtras)
 @property (nonatomic, readonly) BOOL web_containsFileURLAndFileUploadContent;
+@property (nonatomic, readonly) NSArray<NSString *> *web_fileUploadContentTypes;
 @end
 
 /*! A WebItemProviderRegistrar encapsulates a single call to register something to an item provider.
index 816a30f..db9e955 100644 (file)
@@ -487,11 +487,6 @@ static UIPreferredPresentationStyle uiPreferredPresentationStyle(WebPreferredPre
     _supportedTypeIdentifiers = types;
 }
 
-- (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index
-{
-    return [self itemProviderAtIndex:index].registeredTypeIdentifiers ?: @[ ];
-}
-
 - (NSArray<NSString *> *)pasteboardTypes
 {
     NSMutableSet<NSString *> *allTypes = [NSMutableSet set];
index 334a9b2..ee2d34d 100644 (file)
@@ -1,3 +1,54 @@
+2019-02-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
+        https://bugs.webkit.org/show_bug.cgi?id=194670
+        <rdar://problem/39066529>
+
+        Reviewed by Tim Horton.
+
+        Remove all IPC plumbing for getTypesByFidelityForItemAtIndex, now that the types in fidelity order have been
+        rolled into PasteboardItemInfo.
+
+        Additionally, remove support for subresource URL replacement. This feature was originally added with the
+        intention that private clients (i.e. Mail) would intercept pasted or dropped images and replace their URLs.
+        However, since <rdar://problem/43216836>, our strategy for this scenario has changed, such that WebKit now
+        handles the drop/paste, and later delivers the image data to the client via NSFileWrappers in the UI process.
+        At this time, there are no adopters of this SPI, and no adopters of the V2 injected bundle editing client. As
+        such, we can simply revert all of this to its state prior to the introduction of the replacement URL SPI, with
+        the exception to changes in WKBundlePageEditorClient.h, wherein there is a nonzero (but likely tiny) chance of
+        completely breaking binary compatability with any third parties on macOS which may have tried to adopt
+        subresource URL replacement.
+
+        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
+        (WebKit::WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex): Deleted.
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView canPerformActionForWebView:withSender:]):
+
+        Return YES for -paste: in the case where:
+        1. The pasteboard contains items that are explicitly marked as attachments.
+        2. The selection is richly contenteditable.
+        3. Attachment elements are enabled.
+
+        Among other things, this allows the callout bar on iOS to show the "Paste" action.
+
+        * WebProcess/InjectedBundle/API/APIInjectedBundleEditorClient.h:
+        (API::InjectedBundle::EditorClient::performTwoStepDrop):
+        (API::InjectedBundle::EditorClient::replacementURLForResource): Deleted.
+        * WebProcess/InjectedBundle/API/Cocoa/WKWebProcessPlugInEditingDelegate.h:
+        * WebProcess/InjectedBundle/API/mac/WKWebProcessPlugInBrowserContextController.mm:
+        (-[WKWebProcessPlugInBrowserContextController _setEditingDelegate:]):
+        * WebProcess/InjectedBundle/InjectedBundlePageEditorClient.cpp:
+        (WebKit::InjectedBundlePageEditorClient::replacementURLForResource): Deleted.
+        * WebProcess/InjectedBundle/InjectedBundlePageEditorClient.h:
+        * WebProcess/WebCoreSupport/WebEditorClient.cpp:
+        (WebKit::WebEditorClient::replacementURLForResource): Deleted.
+        * WebProcess/WebCoreSupport/WebEditorClient.h:
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
+        (WebKit::WebPlatformStrategies::getTypesByFidelityForItemAtIndex): Deleted.
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
+
 2019-02-18  Jeremy Jones  <jeremyj@apple.com>
 
         exitFullscreen should not instantiate a new model/interface mapping.
index 1dad704..ba4d78e 100644 (file)
@@ -179,10 +179,6 @@ void WebPasteboardProxy::writeCustomData(const WebCore::PasteboardCustomData& da
 }
 
 #if PLATFORM(IOS_FAMILY)
-void WebPasteboardProxy::getPasteboardTypesByFidelityForItemAtIndex(uint64_t index, const String& pasteboardName, Vector<String>& types)
-{
-    PlatformPasteboard(pasteboardName).getTypesByFidelityForItemAtIndex(types, index);
-}
 
 void WebPasteboardProxy::writeURLToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
index 349f1ae..2564d13 100644 (file)
@@ -69,7 +69,6 @@ private:
     void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override;
 
 #if PLATFORM(IOS_FAMILY)
-    void getPasteboardTypesByFidelityForItemAtIndex(uint64_t index, const String& pasteboardName, Vector<String>& types);
     void writeURLToPasteboard(const WebCore::PasteboardURL&, const String& pasteboardName);
     void writeWebContentToPasteboard(const WebCore::PasteboardWebContent&, const String& pasteboardName);
     void writeImageToPasteboard(const WebCore::PasteboardImage&, const String& pasteboardName);
index f5d0d6b..164f29f 100644 (file)
@@ -33,7 +33,6 @@ messages -> WebPasteboardProxy {
     AllPasteboardItemInfo(String pasteboardName) -> (Vector<WebCore::PasteboardItemInfo> allInfo) LegacySync
     InformationForItemAtIndex(uint64_t index, String pasteboardName) -> (struct WebCore::PasteboardItemInfo info) LegacySync
     UpdateSupportedTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
-    GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types) LegacySync
 #endif
 
     WriteCustomData(struct WebCore::PasteboardCustomData data, String pasteboardName) -> (uint64_t changeCount) LegacySync
index d7c14ce..7bd80fd 100644 (file)
@@ -2732,6 +2732,15 @@ WEBCORE_COMMAND_FOR_WEBVIEW(pasteAndMatchStyle);
         if ([pasteboard containsPasteboardTypes:types inItemSet:indices])
             return YES;
 
+#if PLATFORM(IOS)
+        if (editorState.isContentRichlyEditable && _webView.configuration._attachmentElementEnabled) {
+            for (NSItemProvider *itemProvider in pasteboard.itemProviders) {
+                if (itemProvider.preferredPresentationStyle == UIPreferredPresentationStyleAttachment && itemProvider.web_fileUploadContentTypes.count)
+                    return YES;
+            }
+        }
+#endif // PLATFORM(IOS)
+
         auto focusedDocumentOrigin = editorState.originIdentifierForPasteboard;
         if (focusedDocumentOrigin.isEmpty())
             return NO;
index ea3dd1b..696cffc 100644 (file)
@@ -66,7 +66,6 @@ public:
     virtual void getPasteboardDataForRange(WebKit::WebPage&, WebCore::Range*, Vector<WTF::String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) { }
     virtual void didWriteToPasteboard(WebKit::WebPage&) { }
     virtual bool performTwoStepDrop(WebKit::WebPage&, WebCore::DocumentFragment&, WebCore::Range&, bool) { return false; }
-    virtual WTF::String replacementURLForResource(WebKit::WebPage&, Ref<WebCore::SharedBuffer>&&, const WTF::String&) { return { }; }
 };
 
 } // namespace InjectedBundle
index e9acb2d..c8209a1 100644 (file)
@@ -61,7 +61,6 @@ WK_API_AVAILABLE(macosx(10.12.3), ios(10.3))
 - (NSDictionary<NSString *, NSData *> *)_webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller pasteboardDataForRange:(WKWebProcessPlugInRangeHandle *)range;
 - (void)_webProcessPlugInBrowserContextControllerDidWriteToPasteboard:(WKWebProcessPlugInBrowserContextController *)controller;
 - (BOOL)_webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller performTwoStepDrop:(WKWebProcessPlugInNodeHandle *)fragment atDestination:(WKWebProcessPlugInRangeHandle *)destination isMove:(BOOL)isMove WK_API_AVAILABLE(macosx(10.13), ios(11.0));
-- (NSString *)_webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller replacementURLForResource:(NSData *)resourceData mimeType:(NSString *)mimeType WK_API_AVAILABLE(macosx(10.14), ios(12.0));
 
 @end
 
index 8cdf095..6bea51a 100644 (file)
@@ -663,16 +663,6 @@ static inline WKEditorInsertAction toWK(WebCore::EditorInsertAction action)
             return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller performTwoStepDrop:wrapper(*nodeHandle) atDestination:wrapper(*rangeHandle) isMove:isMove];
         }
 
-        WTF::String replacementURLForResource(WebKit::WebPage&, Ref<WebCore::SharedBuffer>&& resourceData, const WTF::String& mimeType)
-        {
-            if (!m_delegateMethods.replacementURLForResource)
-                return { };
-
-            NSString *type = (NSString *)mimeType;
-            auto data = resourceData->createNSData();
-            return [m_controller->_editingDelegate.get() _webProcessPlugInBrowserContextController:m_controller replacementURLForResource:data.get() mimeType:type];
-        }
-
         WKWebProcessPlugInBrowserContextController *m_controller;
         const struct DelegateMethods {
             DelegateMethods(RetainPtr<id <WKWebProcessPlugInEditingDelegate>> delegate)
@@ -683,7 +673,6 @@ static inline WKEditorInsertAction toWK(WebCore::EditorInsertAction action)
                 , getPasteboardDataForRange([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:pasteboardDataForRange:)])
                 , didWriteToPasteboard([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextControllerDidWriteToPasteboard:)])
                 , performTwoStepDrop([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:performTwoStepDrop:atDestination:isMove:)])
-                , replacementURLForResource([delegate respondsToSelector:@selector(_webProcessPlugInBrowserContextController:replacementURLForResource:mimeType:)])
             {
             }
 
@@ -694,7 +683,6 @@ static inline WKEditorInsertAction toWK(WebCore::EditorInsertAction action)
             bool getPasteboardDataForRange;
             bool didWriteToPasteboard;
             bool performTwoStepDrop;
-            bool replacementURLForResource;
         } m_delegateMethods;
     };
 
index 9512302..ce027b5 100644 (file)
@@ -190,14 +190,4 @@ void InjectedBundlePageEditorClient::didWriteToPasteboard(WebPage& page)
         m_client.didWriteToPasteboard(toAPI(&page), m_client.base.clientInfo);
 }
 
-String InjectedBundlePageEditorClient::replacementURLForResource(WebPage& page, Ref<SharedBuffer>&& resourceData, const String& mimeType)
-{
-    if (!m_client.replacementURLForResource)
-        return { };
-
-    auto data = adoptWK(WKDataCreate(reinterpret_cast<const unsigned char*>(resourceData->data()), resourceData->size()));
-    auto type = adoptWK(toCopiedAPI(mimeType));
-    return toWTFString(m_client.replacementURLForResource(toAPI(&page), data.get(), type.get(), m_client.base.clientInfo));
-}
-
 } // namespace WebKit
index 1d976b6..689941a 100644 (file)
@@ -31,7 +31,7 @@
 
 namespace API {
 template<> struct ClientTraits<WKBundlePageEditorClientBase> {
-    typedef std::tuple<WKBundlePageEditorClientV0, WKBundlePageEditorClientV1, WKBundlePageEditorClientV2> Versions;
+    typedef std::tuple<WKBundlePageEditorClientV0, WKBundlePageEditorClientV1> Versions;
 };
 }
 
@@ -67,7 +67,6 @@ private:
     void getPasteboardDataForRange(WebPage&, WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final;
     void didWriteToPasteboard(WebPage&) final;
     bool performTwoStepDrop(WebPage&, WebCore::DocumentFragment&, WebCore::Range& destination, bool isMove) final;
-    String replacementURLForResource(WebPage&, Ref<WebCore::SharedBuffer>&& resourceData, const String&) final;
 };
 
 } // namespace WebKit
index 96a4dd1..9340571 100644 (file)
@@ -297,11 +297,6 @@ bool WebEditorClient::performTwoStepDrop(DocumentFragment& fragment, Range& dest
     return m_page->injectedBundleEditorClient().performTwoStepDrop(*m_page, fragment, destination, isMove);
 }
 
-String WebEditorClient::replacementURLForResource(Ref<WebCore::SharedBuffer>&& resourceData, const String& mimeType)
-{
-    return m_page->injectedBundleEditorClient().replacementURLForResource(*m_page, WTFMove(resourceData), mimeType);
-}
-
 void WebEditorClient::registerUndoStep(UndoStep& step)
 {
     // FIXME: Add assertion that the command being reapplied is the same command that is
index 7be8ddf..b12ba60 100644 (file)
@@ -83,7 +83,6 @@ private:
     void willWriteSelectionToPasteboard(WebCore::Range*) final;
     void didWriteSelectionToPasteboard() final;
     void getClientPasteboardDataForRange(WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final;
-    String replacementURLForResource(Ref<WebCore::SharedBuffer>&& resourceData, const String& mimeType) final;
     
     void registerUndoStep(WebCore::UndoStep&) final;
     void registerRedoStep(WebCore::UndoStep&) final;
index 1fad3cb..3466624 100644 (file)
@@ -245,10 +245,6 @@ int WebPlatformStrategies::getNumberOfFiles(const String& pasteboardName)
 }
 
 #if PLATFORM(IOS_FAMILY)
-void WebPlatformStrategies::getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName)
-{
-    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex(index, pasteboardName), Messages::WebPasteboardProxy::GetPasteboardTypesByFidelityForItemAtIndex::Reply(types), 0);
-}
 
 void WebPlatformStrategies::writeToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
index dc26176..f7f1041 100644 (file)
@@ -57,7 +57,6 @@ private:
     Vector<WebCore::PasteboardItemInfo> allPasteboardItemInfo(const String& pasteboardName) override;
     WebCore::PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) override;
     void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) override;
-    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
 #endif
 #if PLATFORM(COCOA)
     int getNumberOfFiles(const String& pasteboardName) override;
index 5f40b79..d4132c3 100644 (file)
@@ -1,3 +1,18 @@
+2019-02-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
+        https://bugs.webkit.org/show_bug.cgi?id=194670
+        <rdar://problem/39066529>
+
+        Reviewed by Tim Horton.
+
+        * WebCoreSupport/WebEditorClient.h:
+        * WebCoreSupport/WebEditorClient.mm:
+        (WebEditorClient::replacementURLForResource): Deleted.
+        * WebCoreSupport/WebPlatformStrategies.h:
+        * WebCoreSupport/WebPlatformStrategies.mm:
+        (WebPlatformStrategies::getTypesByFidelityForItemAtIndex): Deleted.
+
 2019-02-18  Eric Carlson  <eric.carlson@apple.com>
 
         Add MSE logging configuration
index 55f40e0..e4c2fd6 100644 (file)
@@ -78,7 +78,6 @@ private:
     void willWriteSelectionToPasteboard(WebCore::Range*) final;
     void didWriteSelectionToPasteboard() final;
     void getClientPasteboardDataForRange(WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final;
-    String replacementURLForResource(Ref<WebCore::SharedBuffer>&& resourceData, const String& mimeType) final;
 
     void setInsertionPasteboard(const String&) final;
     bool requestDOMPasteAccess() final { return false; }
index c35233e..0fc814f 100644 (file)
@@ -419,12 +419,6 @@ void WebEditorClient::getClientPasteboardDataForRange(WebCore::Range*, Vector<St
     // Not implemented WebKit, only WebKit2.
 }
 
-String WebEditorClient::replacementURLForResource(Ref<SharedBuffer>&&, const String&)
-{
-    // Not implemented in WebKitLegacy.
-    return { };
-}
-
 #if (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300)
 
 // FIXME: Remove both this stub and the real version of this function below once we don't need the real version on any supported platform.
index 4767b88..d160a83 100644 (file)
@@ -58,7 +58,6 @@ private:
     Vector<WebCore::PasteboardItemInfo> allPasteboardItemInfo(const String& pasteboardName) override;
     WebCore::PasteboardItemInfo informationForItemAtIndex(int index, const String& pasteboardName) override;
     void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) override;
-    void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
 #endif
     int getNumberOfFiles(const String& pasteboardName) override;
     void getTypes(Vector<String>& types, const String& pasteboardName) override;
index 6c1dcb3..08a9026 100644 (file)
@@ -158,10 +158,6 @@ long WebPlatformStrategies::writeCustomData(const WebCore::PasteboardCustomData&
 }
 
 #if PLATFORM(IOS_FAMILY)
-void WebPlatformStrategies::getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName)
-{
-    PlatformPasteboard(pasteboardName).getTypesByFidelityForItemAtIndex(types, index);
-}
 
 void WebPlatformStrategies::writeToPasteboard(const PasteboardURL& url, const String& pasteboardName)
 {
index c6688d1..3b78c27 100644 (file)
@@ -1,3 +1,15 @@
+2019-02-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
+        https://bugs.webkit.org/show_bug.cgi?id=194670
+        <rdar://problem/39066529>
+
+        Reviewed by Tim Horton.
+
+        * WebCoreSupport/WebEditorClient.cpp:
+        (WebEditorClient::replacementURLForResource): Deleted.
+        * WebCoreSupport/WebEditorClient.h:
+
 2019-02-10  Darin Adler  <darin@apple.com>
 
         Replace more uses of String::format with StringConcatenate (mostly non-Apple platform-specific cases)
index 2e7ea58..2e89d41 100644 (file)
@@ -269,12 +269,6 @@ void WebEditorClient::getClientPasteboardDataForRange(WebCore::Range*, Vector<St
     notImplemented();
 }
 
-String WebEditorClient::replacementURLForResource(Ref<WebCore::SharedBuffer>&&, const String&)
-{
-    notImplemented();
-    return { };
-}
-
 bool WebEditorClient::shouldDeleteRange(Range* range)
 {
     COMPtr<IWebEditingDelegate> ed;
index cc5e4d6..b70f7cb 100644 (file)
@@ -54,7 +54,6 @@ private:
     void willWriteSelectionToPasteboard(WebCore::Range*) final;
     void didWriteSelectionToPasteboard() final;
     void getClientPasteboardDataForRange(WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer>>& pasteboardData) final;
-    String replacementURLForResource(Ref<WebCore::SharedBuffer>&&, const String&) final;
 
     void didEndUserTriggeredSelectionChanges() final { }
     void respondToChangedContents() final;
index b9e2f12..5bc63b0 100644 (file)
@@ -1,3 +1,22 @@
+2019-02-18  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Support pasting item-provider-backed data on the pasteboard as attachment elements
+        https://bugs.webkit.org/show_bug.cgi?id=194670
+        <rdar://problem/39066529>
+
+        Reviewed by Tim Horton.
+
+        Remove code and tests for subresource URL replacement, and also add a new test to verify that copied data can be
+        pasted in an editable area as attachment elements.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/BundleEditingDelegatePlugIn.mm:
+        (-[BundleEditingDelegatePlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+        (-[BundleEditingDelegatePlugIn _webProcessPlugInBrowserContextController:replacementURLForResource:mimeType:]): Deleted.
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+        (TestWebKitAPI::TEST):
+        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+        (WTR::InjectedBundlePage::InjectedBundlePage):
+
 2019-02-18  Alex Christensen  <achristensen@webkit.org>
 
         Fix API test after r241728
index 33f2bb8..c63c0a8 100644 (file)
@@ -47,7 +47,6 @@
     RetainPtr<id <BundleEditingDelegateProtocol>> _remoteObject;
     BOOL _editingDelegateShouldInsertText;
     BOOL _shouldOverridePerformTwoStepDrop;
-    RetainPtr<NSDictionary<NSString *, NSString *>> _mimeTypeToReplacementURLMap;
 }
 
 - (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController didCreateBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController
@@ -64,7 +63,6 @@
         _editingDelegateShouldInsertText = YES;
 
     _shouldOverridePerformTwoStepDrop = [[plugInController.parameters valueForKey:@"BundleOverridePerformTwoStepDrop"] boolValue];
-    _mimeTypeToReplacementURLMap = [plugInController.parameters valueForKey:@"MIMETypeToReplacementURLMap"];
 
     _WKRemoteObjectInterface *interface = [_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(BundleEditingDelegateProtocol)];
     _remoteObject = [browserContextController._remoteObjectRegistry remoteObjectProxyWithInterface:interface];
     return _shouldOverridePerformTwoStepDrop;
 }
 
-- (NSString *)_webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller replacementURLForResource:(NSData *)resourceData mimeType:(NSString *)mimeType
-{
-    assert(!!resourceData);
-    return [_mimeTypeToReplacementURLMap objectForKey:mimeType];
-}
-
 @end
 
 #endif // WK_API_ENABLED
index b00ef89..84864fc 100644 (file)
@@ -1158,39 +1158,6 @@ TEST(WKAttachmentTests, InsertDuplicateAttachmentAndUpdateData)
     EXPECT_FALSE([[originalAttachment info].fileWrapper isEqual:fileWrapper.get()]);
 }
 
-TEST(WKAttachmentTests, InjectedBundleReplaceURLsWhenPastingAttributedString)
-{
-    platformCopyRichTextWithMultipleAttachments();
-
-    auto configuration = retainPtr([WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"]);
-    [[configuration processPool] _setObject:@{ @"image/png" : @"cid:foo-bar" } forBundleParameter:@"MIMETypeToReplacementURLMap"];
-    auto webView = webViewForTestingAttachments(CGSizeMake(500, 500), configuration.get());
-    {
-        ObserveAttachmentUpdatesForScope observer(webView.get());
-        [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
-        EXPECT_EQ(2U, observer.observer().inserted.count);
-    }
-    [webView expectElementTagsInOrder:@[ @"IMG", @"ATTACHMENT", @"ATTACHMENT" ]];
-    EXPECT_WK_STREQ("cid:foo-bar", [webView valueOfAttribute:@"src" forQuerySelector:@"img"]);
-    EXPECT_WK_STREQ(@"", [webView stringByEvaluatingJavaScript:@"document.querySelectorAll('img')[0].attachmentIdentifier"]);
-}
-
-TEST(WKAttachmentTests, InjectedBundleReplaceURLWhenPastingImage)
-{
-    platformCopyPNG();
-
-    NSString *replacementURL = @"cid:foo-bar";
-    auto configuration = retainPtr([WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"BundleEditingDelegatePlugIn"]);
-    [[configuration processPool] _setObject:@{ @"image/tiff" : replacementURL, @"image/png" : replacementURL } forBundleParameter:@"MIMETypeToReplacementURLMap"];
-    auto webView = webViewForTestingAttachments(CGSizeMake(500, 500), configuration.get());
-    {
-        ObserveAttachmentUpdatesForScope observer(webView.get());
-        [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
-        EXPECT_EQ(0U, observer.observer().inserted.count);
-    }
-    EXPECT_WK_STREQ("cid:foo-bar", [webView valueOfAttribute:@"src" forQuerySelector:@"img"]);
-}
-
 TEST(WKAttachmentTests, InsertAttachmentUsingFileWrapperWithFilePath)
 {
     auto webView = webViewForTestingAttachments();
@@ -1881,6 +1848,49 @@ TEST(WKAttachmentTestsIOS, InsertDroppedContactAsAttachment)
     EXPECT_WK_STREQ("text/vcard", info.contentType);
 }
 
+TEST(WKAttachmentTestsIOS, InsertPastedFilesAsAttachments)
+{
+    auto pdfItem = adoptNS([[NSItemProvider alloc] init]);
+    [pdfItem setSuggestedName:@"doc"];
+    [pdfItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
+    [pdfItem registerData:testPDFData() type:(__bridge NSString *)kUTTypePDF];
+
+    auto textItem = adoptNS([[NSItemProvider alloc] init]);
+    [textItem setSuggestedName:@"hello"];
+    [textItem setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
+    [textItem registerData:[@"helloworld" dataUsingEncoding:NSUTF8StringEncoding] type:(__bridge NSString *)kUTTypePlainText];
+
+    UIPasteboard.generalPasteboard.itemProviders = @[ pdfItem.get(), textItem.get() ];
+
+    RetainPtr<_WKAttachment> textAttachment;
+    RetainPtr<_WKAttachment> pdfAttachment;
+    auto webView = webViewForTestingAttachments();
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
+        EXPECT_EQ(2U, observer.observer().inserted.count);
+        _WKAttachment *firstAttachment = observer.observer().inserted.firstObject;
+        if ([firstAttachment.info.contentType isEqualToString:@"text/plain"]) {
+            textAttachment = firstAttachment;
+            pdfAttachment = observer.observer().inserted.lastObject;
+        } else {
+            EXPECT_WK_STREQ(firstAttachment.info.contentType, @"application/pdf");
+            textAttachment = observer.observer().inserted.lastObject;
+            pdfAttachment = firstAttachment;
+        }
+        observer.expectAttachmentUpdates(@[ ], @[ pdfAttachment.get(), textAttachment.get() ]);
+    }
+
+    [webView expectElementCount:2 querySelector:@"attachment"];
+    EXPECT_WK_STREQ("doc", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment[type^=application]"]);
+    EXPECT_WK_STREQ("doc", [pdfAttachment info].name);
+    EXPECT_WK_STREQ("hello", [webView valueOfAttribute:@"title" forQuerySelector:@"attachment[type^=text]"]);
+    EXPECT_WK_STREQ("hello", [textAttachment info].name);
+    [pdfAttachment expectRequestedDataToBe:testPDFData()];
+    [textAttachment expectRequestedDataToBe:[@"helloworld" dataUsingEncoding:NSUTF8StringEncoding]];
+    EXPECT_TRUE([webView canPerformAction:@selector(paste:) withSender:nil]);
+}
+
 #if HAVE(PENCILKIT)
 static BOOL forEachViewInHierarchy(UIView *view, void(^mapFunction)(UIView *subview, BOOL *stop))
 {
index 5281d05..653c544 100644 (file)
@@ -358,8 +358,8 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
     };
     WKBundlePageSetUIClient(m_page, &uiClient.base);
 
-    WKBundlePageEditorClientV2 editorClient = {
-        { 2, this },
+    WKBundlePageEditorClientV1 editorClient = {
+        { 1, this },
         shouldBeginEditing,
         shouldEndEditing,
         shouldInsertNode,
@@ -375,7 +375,6 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
         0, /* getPasteboardDataForRange */
         0, /* didWriteToPasteboard */
         0, /* performTwoStepDrop */
-        0, /* replacementURLForResource */
     };
     WKBundlePageSetEditorClient(m_page, &editorClient.base);