[iOS] DataTransfer.getData always returns the empty string when dropping text
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Jun 2018 23:52:57 +0000 (23:52 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Jun 2018 23:52:57 +0000 (23:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187130
<rdar://problem/41014117>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Currently, DataTransfer.getData() always returns the empty string on drop. This is because all data on drop is
backed by local files in the temporary directory, so the number of files is never 0; this, combined with the
fact that WebKit will suppress access to the DataTransfer object if there is one or more file in the pasteboard,
means that getData() never works for drag and drop on iOS at the moment. To fix this, we need to know whether a
dropped item provider is a file.

Ideally, we'd have a flag to tell us whether or not an NSItemProvider being dropped is a file, or instead just
inline data - in fact, this flag already exists in the form of UIPreferredPresentationStyle. Unfortunately, not
all apps that vend draggable files specify this, so we can't simply ask the item provider whether it's intended
to be a file. As a workaround, we can use several heuristics to determine the "file content state" of the drag
pasteboard on iOS (see below for more details).

This patch adds some plumbing through the client layers to grab a list of item information describing each
dropped item provider on iOS. Using this information, we tweak the logic in Pasteboard::fileContentState to make
an educated guess at whether or not the pasteboard really contains files; if we determine that the pasteboard
probably contains no files, we'll allow DataTransfer.getData() to retrieve information from the pasteboard.
Otherwise, if the pasteboard may contain files, we'll fall back to our current behavior of including the "Files"
type in DataTransfer.types and allowing the page to grab file data using DataTransfer.files or
DataTransfer.items.

Tests:  DataInteractionTests.DataTransferGetDataReadPlainAndRichText
        DataInteractionTests.DataTransferSuppressGetDataDueToPresenceOfTextFile

* dom/DataTransfer.cpp:
(WebCore::DataTransfer::filesFromPasteboardAndItemList const):

Check Pasteboard::fileContentState() to ensure that we don't expose files when DataTransfer.types does not
contain the "Files" type, and vice versa, and DataTranser.files is also empty in this case.

* dom/DataTransferItemList.cpp:
* platform/PasteboardItemInfo.h:

Add a couple of additional members to PasteboardItemInfo: suggestedFileName and hasDeclaredNonTextType, a flag
that indicates whether or not the pasteboard item has a type representation that is a declared type, but is not
a text type (i.e. does not conform to "public.text", "public.url", or rich text format with attachment types).

(WebCore::PasteboardItemInfo::encode const):
(WebCore::PasteboardItemInfo::decode):
* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/cocoa/PasteboardCocoa.mm:
(WebCore::Pasteboard::fileContentState):

Instead of always considering a dropped item provider on iOS to represent a file, only do so if at least one of
the following conditions are met:
- The drop session contains multiple item providers (flocking text selections is a very rare use case).
- The item provider was explicitly marked as an attachment.
- The item provider has a suggested file name.
- The item provider has any other content that is not text.

In the case where none of the above conditions are met, the item provider (if it ends up being a file) is
essentially indistinguishable from inline data. An example of this is dropping a plain text file that is
unnamed, with no presentation style, and alongside no other items nor other known type representations. These
are cases in which whether the item is treated as a file or as inline data is (hopefully) irrelevant.

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

Source/WebKit:

Add plumbing to grab information for each item in the pasteboard. See WebCore ChangeLog for more detail.

* UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
(WebKit::WebPasteboardProxy::allPasteboardItemInfo):
* UIProcess/WebPasteboardProxy.h:
* UIProcess/WebPasteboardProxy.messages.in:
* WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
(WebKit::WebPlatformStrategies::allPasteboardItemInfo):
* WebProcess/WebCoreSupport/WebPlatformStrategies.h:

Source/WebKitLegacy/mac:

Add plumbing to grab information for each item in the pasteboard. See WebCore ChangeLog for more detail.

* WebCoreSupport/WebPlatformStrategies.h:
* WebCoreSupport/WebPlatformStrategies.mm:
(WebPlatformStrategies::allPasteboardItemInfo):

Tools:

Add 2 new API tests to verify that:
-   When dropping an item with text, markup, and URL representations, the page is allowed to get "text/html",
    "text/plain" and "text/uri-list" data.
-   Adding a suggested name to a plain text item causes WebKit to treat it as a file, and suppress access to
    DataTransfer.getData().

Additionally tweaks a couple of existing API tests. Namely, in two API tests
(ExternalSourceOverrideDropFileUpload and ExternalSourceHTMLToUploadArea) only a markup string is dropped, and
we previously expected to handle the drop as a file. To allow this test to continue serving its purpose, tweak
them such that the registered items appear to be file-backed (i.e. by adding a suggested filename in one of the
tests, and specifying UIPreferredPresentationStyleAttachment in the other).

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

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/platform/PasteboardItemInfo.h
Source/WebCore/platform/PasteboardStrategy.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/cocoa/PasteboardCocoa.mm
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
Source/WebKit/UIProcess/WebPasteboardProxy.h
Source/WebKit/UIProcess/WebPasteboardProxy.messages.in
Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebPlatformStrategies.h
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.h
Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm

index b878061..8924a83 100644 (file)
@@ -1,3 +1,70 @@
+2018-06-28  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] DataTransfer.getData always returns the empty string when dropping text
+        https://bugs.webkit.org/show_bug.cgi?id=187130
+        <rdar://problem/41014117>
+
+        Reviewed by Ryosuke Niwa.
+
+        Currently, DataTransfer.getData() always returns the empty string on drop. This is because all data on drop is
+        backed by local files in the temporary directory, so the number of files is never 0; this, combined with the
+        fact that WebKit will suppress access to the DataTransfer object if there is one or more file in the pasteboard,
+        means that getData() never works for drag and drop on iOS at the moment. To fix this, we need to know whether a
+        dropped item provider is a file.
+
+        Ideally, we'd have a flag to tell us whether or not an NSItemProvider being dropped is a file, or instead just
+        inline data - in fact, this flag already exists in the form of UIPreferredPresentationStyle. Unfortunately, not
+        all apps that vend draggable files specify this, so we can't simply ask the item provider whether it's intended
+        to be a file. As a workaround, we can use several heuristics to determine the "file content state" of the drag
+        pasteboard on iOS (see below for more details).
+
+        This patch adds some plumbing through the client layers to grab a list of item information describing each
+        dropped item provider on iOS. Using this information, we tweak the logic in Pasteboard::fileContentState to make
+        an educated guess at whether or not the pasteboard really contains files; if we determine that the pasteboard
+        probably contains no files, we'll allow DataTransfer.getData() to retrieve information from the pasteboard.
+        Otherwise, if the pasteboard may contain files, we'll fall back to our current behavior of including the "Files"
+        type in DataTransfer.types and allowing the page to grab file data using DataTransfer.files or
+        DataTransfer.items.
+
+        Tests:  DataInteractionTests.DataTransferGetDataReadPlainAndRichText
+                DataInteractionTests.DataTransferSuppressGetDataDueToPresenceOfTextFile
+
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::filesFromPasteboardAndItemList const):
+
+        Check Pasteboard::fileContentState() to ensure that we don't expose files when DataTransfer.types does not
+        contain the "Files" type, and vice versa, and DataTranser.files is also empty in this case.
+
+        * dom/DataTransferItemList.cpp:
+        * platform/PasteboardItemInfo.h:
+
+        Add a couple of additional members to PasteboardItemInfo: suggestedFileName and hasDeclaredNonTextType, a flag
+        that indicates whether or not the pasteboard item has a type representation that is a declared type, but is not
+        a text type (i.e. does not conform to "public.text", "public.url", or rich text format with attachment types).
+
+        (WebCore::PasteboardItemInfo::encode const):
+        (WebCore::PasteboardItemInfo::decode):
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/cocoa/PasteboardCocoa.mm:
+        (WebCore::Pasteboard::fileContentState):
+
+        Instead of always considering a dropped item provider on iOS to represent a file, only do so if at least one of
+        the following conditions are met:
+        - The drop session contains multiple item providers (flocking text selections is a very rare use case).
+        - The item provider was explicitly marked as an attachment.
+        - The item provider has a suggested file name.
+        - The item provider has any other content that is not text.
+
+        In the case where none of the above conditions are met, the item provider (if it ends up being a file) is
+        essentially indistinguishable from inline data. An example of this is dropping a plain text file that is
+        unnamed, with no presentation style, and alongside no other items nor other known type representations. These
+        are cases in which whether the item is treated as a file or as inline data is (hopefully) irrelevant.
+
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::allPasteboardItemInfo):
+        (WebCore::PlatformPasteboard::informationForItemAtIndex):
+
 2018-06-28  Timothy Hatcher  <timothy@apple.com>
 
         Don't force black text when TextIndicator draws backgrounds or all content.
index 2b91748..5141f47 100644 (file)
@@ -327,7 +327,7 @@ Vector<Ref<File>> DataTransfer::filesFromPasteboardAndItemList() const
 {
     bool addedFilesFromPasteboard = false;
     Vector<Ref<File>> files;
-    if (!forDrag() || forFileDrag()) {
+    if ((!forDrag() || forFileDrag()) && m_pasteboard->fileContentState() != Pasteboard::FileContentState::NoFileOrImageData) {
         WebCorePasteboardFileReader reader;
         m_pasteboard->read(reader);
         files = WTFMove(reader.files);
index f7c35d2..4dfd674 100644 (file)
@@ -39,6 +39,8 @@ enum class PasteboardItemPresentationStyle {
 struct PasteboardItemInfo {
     String pathForFileUpload;
     String contentTypeForFileUpload;
+    String suggestedFileName;
+    bool isNonTextType { false };
     PasteboardItemPresentationStyle preferredPresentationStyle { PasteboardItemPresentationStyle::Unspecified };
 
     template<class Encoder> void encode(Encoder&) const;
@@ -48,7 +50,7 @@ struct PasteboardItemInfo {
 template<class Encoder>
 void PasteboardItemInfo::encode(Encoder& encoder) const
 {
-    encoder << pathForFileUpload << contentTypeForFileUpload;
+    encoder << pathForFileUpload << contentTypeForFileUpload << suggestedFileName << isNonTextType;
     encoder.encodeEnum(preferredPresentationStyle);
 }
 
@@ -62,6 +64,12 @@ std::optional<PasteboardItemInfo> PasteboardItemInfo::decode(Decoder& decoder)
     if (!decoder.decode(result.contentTypeForFileUpload))
         return std::nullopt;
 
+    if (!decoder.decode(result.suggestedFileName))
+        return std::nullopt;
+
+    if (!decoder.decode(result.isNonTextType))
+        return std::nullopt;
+
     if (!decoder.decodeEnum(result.preferredPresentationStyle))
         return std::nullopt;
 
index 5837d91..68317f4 100644 (file)
@@ -51,6 +51,7 @@ public:
     virtual String readStringFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) = 0;
     virtual RefPtr<SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) = 0;
     virtual URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) = 0;
+    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;
index 2488053..3caa549 100644 (file)
@@ -60,6 +60,7 @@ public:
     WEBCORE_EXPORT explicit PlatformPasteboard(const String& pasteboardName);
 #if PLATFORM(IOS) || PLATFORM(WPE)
     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);
index 61e5fea..f48e7b8 100644 (file)
@@ -137,6 +137,36 @@ bool Pasteboard::shouldTreatCocoaTypeAsFile(const String& cocoaType)
 Pasteboard::FileContentState Pasteboard::fileContentState()
 {
     bool mayContainFilePaths = platformStrategies()->pasteboardStrategy()->getNumberOfFiles(m_pasteboardName);
+
+#if PLATFORM(IOS)
+    if (mayContainFilePaths) {
+        // On iOS, files are not written to the pasteboard using file URLs, so we need a heuristic to determine
+        // whether or not the pasteboard contains items that represent files. An example of when this gets tricky
+        // is differentiating between cases where the user is dragging a plain text file, versus selected text.
+        // Some common signs that indicate a file drop as opposed to dropping inline data are:
+        //
+        //  1. Multiple items - the system generally does not give opportunities to flock multiple pieces of
+        //     selected text.
+        //  2. Preferred attachment presentation style - this means the source has explicitly marked the item
+        //     as a file-like entity, as opposed to inline data.
+        //  3. A suggested name - this means that the source has explicitly specified a potential file name for
+        //     the item when dropped.
+        //  4. The presence of any other declared non-text data in the same item indicates that the content being
+        //     dropped can take on another non-text format, which could be a file.
+        //
+        // If none of these four conditions are satisfied, it's very likely that the content being dropped is just
+        // an inline piece of text, with no files in the pasteboard (and therefore, no risk of leaking file paths
+        // to web content). In cases such as these, we should not suppress DataTransfer access.
+        auto items = platformStrategies()->pasteboardStrategy()->allPasteboardItemInfo(m_pasteboardName);
+        mayContainFilePaths = items.size() != 1 || notFound != items.findMatching([] (auto& item) {
+            if (item.preferredPresentationStyle != PasteboardItemPresentationStyle::Unspecified)
+                return item.preferredPresentationStyle == PasteboardItemPresentationStyle::Attachment;
+
+            return !item.suggestedFileName.isEmpty() || item.isNonTextType;
+        });
+    }
+#endif
+
     if (!mayContainFilePaths) {
         Vector<String> cocoaTypes;
         platformStrategies()->pasteboardStrategy()->getTypes(cocoaTypes, m_pasteboardName);
index 7ee2ad9..690b8c5 100644 (file)
@@ -122,6 +122,14 @@ static PasteboardItemPresentationStyle pasteboardItemPresentationStyle(UIPreferr
     }
 }
 
+Vector<PasteboardItemInfo> PlatformPasteboard::allPasteboardItemInfo()
+{
+    Vector<PasteboardItemInfo> itemInfo;
+    for (NSInteger itemIndex = 0; itemIndex < [m_pasteboard numberOfItems]; ++itemIndex)
+        itemInfo.append(informationForItemAtIndex(itemIndex));
+    return itemInfo;
+}
+
 PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
 {
     if (index >= [m_pasteboard numberOfItems])
@@ -136,6 +144,28 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int index)
 
     NSItemProvider *itemProvider = [[m_pasteboard itemProviders] objectAtIndex:index];
     info.preferredPresentationStyle = pasteboardItemPresentationStyle(itemProvider.preferredPresentationStyle);
+    info.suggestedFileName = itemProvider.suggestedName;
+    for (NSString *typeIdentifier in itemProvider.registeredTypeIdentifiers) {
+        CFStringRef cfTypeIdentifier = (CFStringRef)typeIdentifier;
+        if (!UTTypeIsDeclared(cfTypeIdentifier))
+            continue;
+
+        if (UTTypeConformsTo(cfTypeIdentifier, kUTTypeText))
+            continue;
+
+        if (UTTypeConformsTo(cfTypeIdentifier, kUTTypeURL))
+            continue;
+
+        if (UTTypeConformsTo(cfTypeIdentifier, kUTTypeRTFD))
+            continue;
+
+        if (UTTypeConformsTo(cfTypeIdentifier, kUTTypeFlatRTFD))
+            continue;
+
+        info.isNonTextType = true;
+        break;
+    }
+
     return info;
 }
 
@@ -146,6 +176,11 @@ PasteboardItemInfo PlatformPasteboard::informationForItemAtIndex(int)
     return { };
 }
 
+Vector<PasteboardItemInfo> PlatformPasteboard::allPasteboardItemInfo()
+{
+    return { };
+}
+
 #endif
 
 static bool pasteboardMayContainFilePaths(id<AbstractPasteboard> pasteboard)
index 40912bb..cc87df8 100644 (file)
@@ -1,3 +1,21 @@
+2018-06-28  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] DataTransfer.getData always returns the empty string when dropping text
+        https://bugs.webkit.org/show_bug.cgi?id=187130
+        <rdar://problem/41014117>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add plumbing to grab information for each item in the pasteboard. See WebCore ChangeLog for more detail.
+
+        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
+        (WebKit::WebPasteboardProxy::allPasteboardItemInfo):
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
+        (WebKit::WebPlatformStrategies::allPasteboardItemInfo):
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
+
 2018-06-28  Youenn Fablet  <youenn@apple.com>
 
         Early return when handling fetch event in case service worker origin does not match origin of a subresource load
index b20122b..ee917e3 100644 (file)
@@ -226,6 +226,11 @@ void WebPasteboardProxy::getPasteboardItemsCount(const String& pasteboardName, u
     itemsCount = PlatformPasteboard(pasteboardName).count();
 }
 
+void WebPasteboardProxy::allPasteboardItemInfo(const String& pasteboardName, Vector<PasteboardItemInfo>& allInfo)
+{
+    allInfo = PlatformPasteboard(pasteboardName).allPasteboardItemInfo();
+}
+
 void WebPasteboardProxy::informationForItemAtIndex(int index, const String& pasteboardName, PasteboardItemInfo& info)
 {
     info = PlatformPasteboard(pasteboardName).informationForItemAtIndex(index);
index e84f8fe..5fb4abc 100644 (file)
@@ -78,6 +78,7 @@ private:
     void readURLFromPasteboard(uint64_t index, const String& pasteboardType, const String& pasteboardName, String& url, String& title);
     void readBufferFromPasteboard(uint64_t index, const String& pasteboardType, const String& pasteboardName, SharedMemory::Handle&, uint64_t& size);
     void getPasteboardItemsCount(const String& pasteboardName, uint64_t& itemsCount);
+    void allPasteboardItemInfo(const String& pasteboardName, Vector<WebCore::PasteboardItemInfo>&);
     void informationForItemAtIndex(int index, const String& pasteboardName, WebCore::PasteboardItemInfo& filename);
     void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName);
 #endif
index c7b3b26..3dc08ed 100644 (file)
@@ -30,6 +30,7 @@ messages -> WebPasteboardProxy {
     ReadURLFromPasteboard(uint64_t index, String pasteboardType, String pasteboardName) -> (String url, String title)
     ReadBufferFromPasteboard(uint64_t index, String pasteboardType, String pasteboardName) -> (WebKit::SharedMemory::Handle handle, uint64_t size)
     GetPasteboardItemsCount(String pasteboardName) -> (uint64_t itemsCount)
+    AllPasteboardItemInfo(String pasteboardName) -> (Vector<WebCore::PasteboardItemInfo> allInfo)
     InformationForItemAtIndex(uint64_t index, String pasteboardName) -> (struct WebCore::PasteboardItemInfo info)
     UpdateSupportedTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
     GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types)
index 97a3270..159f3da 100644 (file)
@@ -322,6 +322,13 @@ int WebPlatformStrategies::getPasteboardItemsCount(const String& pasteboardName)
     return itemsCount;
 }
 
+Vector<PasteboardItemInfo> WebPlatformStrategies::allPasteboardItemInfo(const String& pasteboardName)
+{
+    Vector<PasteboardItemInfo> allInfo;
+    WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::AllPasteboardItemInfo(pasteboardName), Messages::WebPasteboardProxy::AllPasteboardItemInfo::Reply(allInfo), 0);
+    return allInfo;
+}
+
 PasteboardItemInfo WebPlatformStrategies::informationForItemAtIndex(int index, const String& pasteboardName)
 {
     PasteboardItemInfo info;
index 659e763..f8cd305 100644 (file)
@@ -65,6 +65,7 @@ private:
     String readStringFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) override;
+    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;
index 61a2419..9ed9224 100644 (file)
@@ -1,3 +1,17 @@
+2018-06-28  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] DataTransfer.getData always returns the empty string when dropping text
+        https://bugs.webkit.org/show_bug.cgi?id=187130
+        <rdar://problem/41014117>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add plumbing to grab information for each item in the pasteboard. See WebCore ChangeLog for more detail.
+
+        * WebCoreSupport/WebPlatformStrategies.h:
+        * WebCoreSupport/WebPlatformStrategies.mm:
+        (WebPlatformStrategies::allPasteboardItemInfo):
+
 2018-06-26  Eric Carlson  <eric.carlson@apple.com>
 
         [Mac] AirPlay picker uses incorrect theme in Dark mode
index 720fe65..adc2ec4 100644 (file)
@@ -66,6 +66,7 @@ private:
     String readStringFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     RefPtr<WebCore::SharedBuffer> readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName) override;
     WebCore::URL readURLFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName, String& title) override;
+    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;
index ebfcb6f..339bbbf 100644 (file)
@@ -240,6 +240,11 @@ String WebPlatformStrategies::readStringFromPasteboard(int index, const String&
     return PlatformPasteboard(pasteboardName).readString(index, type);
 }
 
+Vector<WebCore::PasteboardItemInfo> WebPlatformStrategies::allPasteboardItemInfo(const String& pasteboardName)
+{
+    return PlatformPasteboard(pasteboardName).allPasteboardItemInfo();
+}
+
 WebCore::PasteboardItemInfo WebPlatformStrategies::informationForItemAtIndex(int index, const String& pasteboardName)
 {
     return PlatformPasteboard(pasteboardName).informationForItemAtIndex(index);
index 4e5022a..74e6daf 100644 (file)
@@ -1,3 +1,26 @@
+2018-06-28  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] DataTransfer.getData always returns the empty string when dropping text
+        https://bugs.webkit.org/show_bug.cgi?id=187130
+        <rdar://problem/41014117>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add 2 new API tests to verify that:
+        -   When dropping an item with text, markup, and URL representations, the page is allowed to get "text/html",
+            "text/plain" and "text/uri-list" data.
+        -   Adding a suggested name to a plain text item causes WebKit to treat it as a file, and suppress access to
+            DataTransfer.getData().
+
+        Additionally tweaks a couple of existing API tests. Namely, in two API tests
+        (ExternalSourceOverrideDropFileUpload and ExternalSourceHTMLToUploadArea) only a markup string is dropped, and
+        we previously expected to handle the drop as a file. To allow this test to continue serving its purpose, tweak
+        them such that the registered items appear to be file-backed (i.e. by adding a suggested filename in one of the
+        tests, and specifying UIPreferredPresentationStyleAttachment in the other).
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
 2018-06-28  Basuke Suzuki  <Basuke.Suzuki@sony.com>
 
         Unreviewed, rolling out r226652.
index d060a22..21b1e17 100644 (file)
@@ -650,6 +650,7 @@ TEST(DataInteractionTests, ExternalSourceHTMLToUploadArea)
     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
     NSData *htmlData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:htmlData];
+    [simulatedHTMLItemProvider setSuggestedName:@"index.html"];
 
     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
     [dataInteractionSimulator setShouldAllowMoveOperation:NO];
@@ -980,6 +981,7 @@ TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
     auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
     NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
     [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
+    [simulatedHTMLItemProvider setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
 
     auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
     [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
@@ -1691,6 +1693,51 @@ TEST(DataInteractionTests, DataTransferSetDataCannotWritePlatformTypes)
     });
 }
 
+TEST(DataInteractionTests, DataTransferGetDataReadPlainAndRichText)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"DataTransfer"];
+    auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+    auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSDictionary *textAttributes = @{ NSFontAttributeName: [UIFont boldSystemFontOfSize:20] };
+    NSAttributedString *richText = [[NSAttributedString alloc] initWithString:@"WebKit" attributes:textAttributes];
+    [itemProvider registerObject:richText visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider registerObject:[NSURL URLWithString:@"https://www.webkit.org/"] visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider registerObject:@"WebKit" visibility:NSItemProviderRepresentationVisibilityAll];
+
+    [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+    [simulator runFrom:CGPointZero to:CGPointMake(50, 100)];
+
+    EXPECT_WK_STREQ("text/html, text/plain, text/uri-list", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+    EXPECT_WK_STREQ("WebKit", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+    EXPECT_WK_STREQ("https://www.webkit.org/", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+    EXPECT_WK_STREQ("WebKit", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+    EXPECT_WK_STREQ("(STRING, text/html), (STRING, text/plain), (STRING, text/uri-list)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+}
+
+TEST(DataInteractionTests, DataTransferSuppressGetDataDueToPresenceOfTextFile)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"DataTransfer"];
+    auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+    auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [itemProvider registerObject:@"Hello world" visibility:NSItemProviderRepresentationVisibilityAll];
+    [itemProvider setSuggestedName:@"hello.txt"];
+
+    [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+    [simulator runFrom:CGPointZero to:CGPointMake(50, 100)];
+
+    EXPECT_WK_STREQ("Files", [webView stringByEvaluatingJavaScript:@"types.textContent"]);
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"textData.textContent"]);
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"urlData.textContent"]);
+    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"htmlData.textContent"]);
+    EXPECT_WK_STREQ("(FILE, text/plain)", [webView stringByEvaluatingJavaScript:@"items.textContent"]);
+    EXPECT_WK_STREQ("('hello.txt', text/plain)", [webView stringByEvaluatingJavaScript:@"files.textContent"]);
+}
+
 TEST(DataInteractionTests, DataTransferGetDataCannotReadPrivateArbitraryTypes)
 {
     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);