WebItemProviderPasteboard should not synchronously load provided data
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Apr 2017 23:33:34 +0000 (23:33 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 26 Apr 2017 23:33:34 +0000 (23:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=171341
<rdar://problem/31614010>

Reviewed by Tim Horton.

Source/WebCore:

Refactors WebItemProviderPasteboard to not require asynchronously loading item provider data. To accomplish this,
we ensure that before performing data interaction, the UTI type that the data operation target should consume is
propagated to the UI process prior to the web process receiving the signal from the UI process to begin the
data operation itself. This information is sent via WebPlatformStrategies::updatePreferredTypeIdentifiers, a new
pasteboard helper function.

* page/DragController.cpp:
(WebCore::DragController::DragController):
(WebCore::dragIsHandledByDocument):
(WebCore::DragController::performDragOperation):
(WebCore::DragController::dragEnteredOrUpdated):
(WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod):
(WebCore::DragController::tryDocumentDrag):

Give DragHandlingMethod a richer representation of what type of action will be performed. DragController::
updatePreferredTypeIdentifiersForDragHandlingMethod uses this to determine what kinds of UTIs are acceptable for
the current drop session.

* page/DragController.h:
(WebCore::DragController::documentIsHandlingNonDefaultDrag):
* page/mac/DragControllerMac.mm:
(WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod):

Updates the data interaction pasteboard's list of preferred type identifiers it should load upon data operation.

* platform/DragData.h:
* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/ios/AbstractPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::updatePreferredTypeIdentifiers):
* platform/ios/WebItemProviderPasteboard.mm:

Introduce _preferredTypeIdentifiers, which -doAfterLoadingProvidedContentIntoFileURLs: uses as a hint when
determining which UTI to load for an item provider. In the absence of preferred type identifiers, the default
behavior is to use the highest fidelity type adhering to "public.content".

(-[WebItemProviderPasteboard init]):
(-[WebItemProviderPasteboard updatePreferredTypeIdentifiers:]):
(-[WebItemProviderPasteboard setItemProviders:]):
(-[WebItemProviderPasteboard dataForPasteboardType:inItemSet:]):
(-[WebItemProviderPasteboard valuesForPasteboardType:inItemSet:]):

Remove calls to -createObjectOfClass: and -copyDataRepresentation:. Instead, rely solely on the loaded file URL
to read and initialize data and objects from the pasteboard.

(-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:]):
(-[WebItemProviderPasteboard _tryToCreateObjectOfClass:usingProvider:]): Deleted.
* platform/mac/DragDataMac.mm:
(WebCore::DragData::updatePreferredTypeIdentifiers):

Source/WebKit/mac:

Adds client-layer plumbing for updatePreferredTypeIdentifiers. See WebCore ChangeLog for more details.

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

Source/WebKit2:

Adds plumbing for updatePreferredTypeIdentifiers through the WebPasteboardProxy. This allows the web process to
signal to the UI process what UTIs the current drop target should accept and load. See WebCore ChangeLog for more
details.

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

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

21 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/DragController.cpp
Source/WebCore/page/DragController.h
Source/WebCore/page/mac/DragControllerMac.mm
Source/WebCore/platform/DragData.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.mm
Source/WebCore/platform/mac/DragDataMac.mm
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebCoreSupport/WebPlatformStrategies.h
Source/WebKit/mac/WebCoreSupport/WebPlatformStrategies.mm
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/Cocoa/WebPasteboardProxyCocoa.mm
Source/WebKit2/UIProcess/WebPasteboardProxy.h
Source/WebKit2/UIProcess/WebPasteboardProxy.messages.in
Source/WebKit2/WebProcess/WebCoreSupport/WebPlatformStrategies.cpp
Source/WebKit2/WebProcess/WebCoreSupport/WebPlatformStrategies.h

index 39ed16c..8c7ff50 100644 (file)
@@ -1,3 +1,62 @@
+2017-04-26  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        WebItemProviderPasteboard should not synchronously load provided data
+        https://bugs.webkit.org/show_bug.cgi?id=171341
+        <rdar://problem/31614010>
+
+        Reviewed by Tim Horton.
+
+        Refactors WebItemProviderPasteboard to not require asynchronously loading item provider data. To accomplish this,
+        we ensure that before performing data interaction, the UTI type that the data operation target should consume is
+        propagated to the UI process prior to the web process receiving the signal from the UI process to begin the
+        data operation itself. This information is sent via WebPlatformStrategies::updatePreferredTypeIdentifiers, a new
+        pasteboard helper function.
+
+        * page/DragController.cpp:
+        (WebCore::DragController::DragController):
+        (WebCore::dragIsHandledByDocument):
+        (WebCore::DragController::performDragOperation):
+        (WebCore::DragController::dragEnteredOrUpdated):
+        (WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod):
+        (WebCore::DragController::tryDocumentDrag):
+
+        Give DragHandlingMethod a richer representation of what type of action will be performed. DragController::
+        updatePreferredTypeIdentifiersForDragHandlingMethod uses this to determine what kinds of UTIs are acceptable for
+        the current drop session.
+
+        * page/DragController.h:
+        (WebCore::DragController::documentIsHandlingNonDefaultDrag):
+        * page/mac/DragControllerMac.mm:
+        (WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod):
+
+        Updates the data interaction pasteboard's list of preferred type identifiers it should load upon data operation.
+
+        * platform/DragData.h:
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::updatePreferredTypeIdentifiers):
+        * platform/ios/WebItemProviderPasteboard.mm:
+
+        Introduce _preferredTypeIdentifiers, which -doAfterLoadingProvidedContentIntoFileURLs: uses as a hint when
+        determining which UTI to load for an item provider. In the absence of preferred type identifiers, the default
+        behavior is to use the highest fidelity type adhering to "public.content".
+
+        (-[WebItemProviderPasteboard init]):
+        (-[WebItemProviderPasteboard updatePreferredTypeIdentifiers:]):
+        (-[WebItemProviderPasteboard setItemProviders:]):
+        (-[WebItemProviderPasteboard dataForPasteboardType:inItemSet:]):
+        (-[WebItemProviderPasteboard valuesForPasteboardType:inItemSet:]):
+
+        Remove calls to -createObjectOfClass: and -copyDataRepresentation:. Instead, rely solely on the loaded file URL
+        to read and initialize data and objects from the pasteboard.
+
+        (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:]):
+        (-[WebItemProviderPasteboard _tryToCreateObjectOfClass:usingProvider:]): Deleted.
+        * platform/mac/DragDataMac.mm:
+        (WebCore::DragData::updatePreferredTypeIdentifiers):
+
 2017-04-26  Joanmarie Diggs  <jdiggs@igalia.com>
 
         [ATK] Elements with a defined, non-false value for aria-current should expose ATK_STATE_ACTIVE
index d73948f..657db33 100644 (file)
@@ -119,7 +119,7 @@ DragController::DragController(Page& page, DragClient& client)
     : m_page(page)
     , m_client(client)
     , m_numberOfItemsToBeAccepted(0)
-    , m_documentDragHandlingMethod(DragHandlingMethod::None)
+    , m_dragHandlingMethod(DragHandlingMethod::None)
     , m_dragDestinationAction(DragDestinationActionNone)
     , m_dragSourceAction(DragSourceActionNone)
     , m_didInitiateDrag(false)
@@ -220,6 +220,17 @@ DragOperation DragController::dragUpdated(const DragData& dragData)
     return dragEnteredOrUpdated(dragData);
 }
 
+inline static bool dragIsHandledByDocument(DragController::DragHandlingMethod dragHandlingMethod)
+{
+    if (dragHandlingMethod == DragController::DragHandlingMethod::None)
+        return false;
+
+    if (dragHandlingMethod == DragController::DragHandlingMethod::PageLoad)
+        return false;
+
+    return true;
+}
+
 bool DragController::performDragOperation(const DragData& dragData)
 {
     m_documentUnderMouse = m_page.mainFrame().documentAtPoint(dragData.clientPosition());
@@ -228,7 +239,7 @@ bool DragController::performDragOperation(const DragData& dragData)
     if (m_documentUnderMouse)
         shouldOpenExternalURLsPolicy = m_documentUnderMouse->shouldOpenExternalURLsPolicyToPropagate();
 
-    if ((m_dragDestinationAction & DragDestinationActionDHTML) && m_documentDragHandlingMethod != DragHandlingMethod::None) {
+    if ((m_dragDestinationAction & DragDestinationActionDHTML) && dragIsHandledByDocument(m_dragHandlingMethod)) {
         m_client.willPerformDragDestinationAction(DragDestinationActionDHTML, dragData);
         Ref<MainFrame> mainFrame(m_page.mainFrame());
         bool preventedDefault = false;
@@ -283,6 +294,7 @@ DragOperation DragController::dragEnteredOrUpdated(const DragData& dragData)
 {
     mouseMovedIntoDocument(m_page.mainFrame().documentAtPoint(dragData.clientPosition()));
 
+    m_preferredTypeIdentifiersToLoad = { };
     m_dragDestinationAction = dragData.dragDestinationAction();
     if (m_dragDestinationAction == DragDestinationActionNone) {
         clearDragCaret(); // FIXME: Why not call mouseMovedIntoDocument(nullptr)?
@@ -290,9 +302,14 @@ DragOperation DragController::dragEnteredOrUpdated(const DragData& dragData)
     }
 
     DragOperation dragOperation = DragOperationNone;
-    m_documentDragHandlingMethod = tryDocumentDrag(dragData, m_dragDestinationAction, dragOperation);
-    if (m_documentDragHandlingMethod == DragHandlingMethod::None && (m_dragDestinationAction & DragDestinationActionLoad))
+    m_dragHandlingMethod = tryDocumentDrag(dragData, m_dragDestinationAction, dragOperation);
+    if (m_dragHandlingMethod == DragHandlingMethod::None && (m_dragDestinationAction & DragDestinationActionLoad)) {
         dragOperation = operationForLoad(dragData);
+        if (dragOperation != DragOperationNone)
+            m_dragHandlingMethod = DragHandlingMethod::PageLoad;
+    }
+
+    updatePreferredTypeIdentifiersForDragHandlingMethod(m_dragHandlingMethod, dragData);
     return dragOperation;
 }
 
@@ -331,6 +348,14 @@ static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint&
     return downcast<Element>(node);
 }
 
+#if !ENABLE(DATA_INTERACTION)
+
+void DragController::updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const
+{
+}
+
+#endif
+
 DragController::DragHandlingMethod DragController::tryDocumentDrag(const DragData& dragData, DragDestinationAction actionMask, DragOperation& dragOperation)
 {
     if (!m_documentUnderMouse)
@@ -365,7 +390,7 @@ DragController::DragHandlingMethod DragController::tryDocumentDrag(const DragDat
     if ((actionMask & DragDestinationActionEdit) && canProcessDrag(dragData)) {
         if (dragData.containsColor()) {
             dragOperation = DragOperationGeneric;
-            return DragHandlingMethod::Default;
+            return DragHandlingMethod::SetColor;
         }
 
         IntPoint point = frameView->windowToContents(dragData.clientPosition());
@@ -408,8 +433,14 @@ DragController::DragHandlingMethod DragController::tryDocumentDrag(const DragDat
             // be loaded into the view the number of dragged items is 1.
             m_numberOfItemsToBeAccepted = numberOfFiles != 1 ? 0 : 1;
         }
-        
-        return DragHandlingMethod::Default;
+
+        if (m_fileInputElementUnderMouse)
+            return DragHandlingMethod::UploadFile;
+
+        if (m_page.dragCaretController().isContentRichlyEditable())
+            return DragHandlingMethod::EditRichText;
+
+        return DragHandlingMethod::EditPlainText;
     }
     
     // We are not over an editable region. Make sure we're clearing any prior drag cursor.
index 12f8c3d..6cc518b 100644 (file)
@@ -79,8 +79,8 @@ struct DragState;
         const IntPoint& dragOffset() const { return m_dragOffset; }
         DragSourceAction dragSourceAction() const { return m_dragSourceAction; }
 
-        enum class DragHandlingMethod { None, Default, NonDefault };
-        bool documentIsHandlingNonDefaultDrag() const { return m_documentDragHandlingMethod == DragHandlingMethod::NonDefault; }
+        enum class DragHandlingMethod { None, EditPlainText, EditRichText, UploadFile, PageLoad, SetColor, NonDefault };
+        bool documentIsHandlingNonDefaultDrag() const { return m_dragHandlingMethod == DragHandlingMethod::NonDefault; }
         Document* documentUnderMouse() const { return m_documentUnderMouse.get(); }
         DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; }
         DragSourceAction delegateDragSourceAction(const IntPoint& rootViewPoint);
@@ -100,6 +100,7 @@ struct DragState;
         static const float DragImageAlpha;
 
     private:
+        void updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const;
         bool dispatchTextInputEventFor(Frame*, const DragData&);
         bool canProcessDrag(const DragData&);
         bool concludeEditDrag(const DragData&);
@@ -132,10 +133,11 @@ struct DragState;
         RefPtr<Document> m_dragInitiator; // The Document (if any) that initiated the drag.
         RefPtr<HTMLInputElement> m_fileInputElementUnderMouse;
         unsigned m_numberOfItemsToBeAccepted;
-        DragHandlingMethod m_documentDragHandlingMethod;
+        DragHandlingMethod m_dragHandlingMethod;
 
         DragDestinationAction m_dragDestinationAction;
         DragSourceAction m_dragSourceAction;
+        Vector<String> m_preferredTypeIdentifiersToLoad;
         bool m_didInitiateDrag;
         DragOperation m_sourceDragOperation; // Set in startDrag when a drag starts from a mouse down within WebKit
         IntPoint m_dragOffset;
index 9287088..e1dcb29 100644 (file)
 #import "Pasteboard.h"
 #import "Range.h"
 
+#if ENABLE(DATA_INTERACTION)
+#import <MobileCoreServices/MobileCoreServices.h>
+#endif
+
 namespace WebCore {
 
 const int DragController::LinkDragBorderInset = -2;
@@ -89,6 +93,33 @@ void DragController::cleanupAfterSystemDrag()
         dragEnded();
 }
 
+#if ENABLE(DATA_INTERACTION)
+
+void DragController::updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod dragHandlingMethod, const DragData& dragData) const
+{
+    Vector<String> supportedTypes;
+    switch (dragHandlingMethod) {
+    case DragHandlingMethod::PageLoad:
+        supportedTypes.append(kUTTypeURL);
+        break;
+    case DragHandlingMethod::EditPlainText:
+        supportedTypes.append(kUTTypeURL);
+        supportedTypes.append(kUTTypeText);
+        supportedTypes.append(kUTTypeUTF8PlainText);
+        break;
+    case DragHandlingMethod::EditRichText:
+        for (NSString *type in Pasteboard::supportedPasteboardTypes())
+            supportedTypes.append(type);
+        break;
+    default:
+        supportedTypes.append(kUTTypeContent);
+        break;
+    }
+    dragData.updatePreferredTypeIdentifiers(supportedTypes);
+}
+
+#endif
+
 #if ENABLE(ATTACHMENT_ELEMENT)
 void DragController::declareAndWriteAttachment(DataTransfer& dataTransfer, Element& element, const URL& url)
 {
index eb74b37..4a9f82d 100644 (file)
@@ -113,6 +113,9 @@ public:
     const String& pasteboardName() const { return m_pasteboardName; }
     bool containsPromise() const;
 #endif
+#if ENABLE(DATA_INTERACTION)
+    void updatePreferredTypeIdentifiers(const Vector<String>& supportedTypes) const;
+#endif
 
 #if PLATFORM(GTK)
 
index e5d891d..d72f120 100644 (file)
@@ -52,6 +52,7 @@ public:
     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 void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) = 0;
+    virtual void updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) = 0;
     virtual void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) = 0;
 #endif // PLATFORM(IOS)
 #if PLATFORM(COCOA)
index 321324c..85a8c9f 100644 (file)
@@ -57,6 +57,7 @@ public:
     WEBCORE_EXPORT PlatformPasteboard();
     WEBCORE_EXPORT Vector<String> filenamesForDataInteraction();
     WEBCORE_EXPORT void getTypesByFidelityForItemAtIndex(Vector<String>& types, int index);
+    WEBCORE_EXPORT void updatePreferredTypeIdentifiers(const Vector<String>& types);
 #endif
     WEBCORE_EXPORT static String uniqueName();
 
index 7cb2dae..e1c2c2c 100644 (file)
@@ -45,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index;
 @property (readonly, nonatomic) NSInteger numberOfFiles;
 @property (readonly, nonatomic) NSArray<NSURL *> *fileURLsForDataInteraction;
+- (void)updatePreferredTypeIdentifiers:(NSArray<NSString *> *)types;
 
 @end
 
index 65a7678..0593760 100644 (file)
@@ -157,6 +157,9 @@ void Pasteboard::read(PasteboardPlainText& text)
     }
 
     text.text = strategy.readStringFromPasteboard(0, kUTTypeText, m_pasteboardName);
+    if (text.text.isEmpty())
+        text.text = strategy.readStringFromPasteboard(0, kUTTypePlainText, m_pasteboardName);
+
     text.isURL = false;
 }
 
index b537d30..9ea69b7 100644 (file)
@@ -376,7 +376,7 @@ String PlatformPasteboard::readString(int index, const String& type)
 
     id value = [pasteboardItem objectAtIndex:0];
     
-    if (type == String(kUTTypeText)) {
+    if (type == String(kUTTypeText) || type == String(kUTTypePlainText)) {
         ASSERT([value isKindOfClass:[NSString class]]);
         if ([value isKindOfClass:[NSString class]])
             return String(value);
@@ -412,4 +412,16 @@ URL PlatformPasteboard::readURL(int index, const String& type, String& title)
     return (NSURL *)value;
 }
 
+void PlatformPasteboard::updatePreferredTypeIdentifiers(const Vector<String>& types)
+{
+    if (![m_pasteboard respondsToSelector:@selector(updatePreferredTypeIdentifiers:)])
+        return;
+
+    NSMutableArray *typesArray = [NSMutableArray arrayWithCapacity:types.size()];
+    for (auto type : types)
+        [typesArray addObject:(NSString *)type];
+
+    [m_pasteboard updatePreferredTypeIdentifiers:typesArray];
+}
+
 }
index 869ae0e..73da44e 100644 (file)
@@ -32,6 +32,7 @@
 #import "UIKitSPI.h"
 #import <Foundation/NSProgress.h>
 #import <MobileCoreServices/MobileCoreServices.h>
+#import <UIKit/NSString+UIItemProvider.h>
 #import <UIKit/NSURL+UIItemProvider.h>
 #import <UIKit/UIColor.h>
 #import <UIKit/UIImage.h>
@@ -60,7 +61,7 @@ static BOOL isRichTextType(NSString *type)
 
 static BOOL isStringType(NSString *type)
 {
-    return MATCHES_UTI_TYPE(type, Text) || MATCHES_UTI_TYPE(type, UTF8PlainText) || MATCHES_UTI_TYPE(type, UTF16PlainText);
+    return MATCHES_UTI_TYPE(type, Text) || MATCHES_UTI_TYPE(type, UTF8PlainText) || MATCHES_UTI_TYPE(type, UTF16PlainText) || MATCHES_UTI_TYPE(type, PlainText);
 }
 
 static BOOL isURLType(NSString *type)
@@ -180,6 +181,7 @@ static BOOL isImageType(NSString *type)
     RetainPtr<NSArray> _itemProviders;
     RetainPtr<NSArray> _cachedTypeIdentifiers;
     RetainPtr<NSArray> _typeToFileURLMaps;
+    RetainPtr<NSArray> _preferredTypeIdentifiers;
 }
 
 + (instancetype)sharedInstance
@@ -199,10 +201,17 @@ static BOOL isImageType(NSString *type)
         _changeCount = 0;
         _pendingOperationCount = 0;
         _typeToFileURLMaps = adoptNS([[NSArray alloc] init]);
+        _preferredTypeIdentifiers = nil;
     }
     return self;
 }
 
+- (void)updatePreferredTypeIdentifiers:(NSArray<NSString *> *)types
+{
+    if ([_itemProviders count] == types.count)
+        _preferredTypeIdentifiers = types;
+}
+
 - (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index
 {
     return [self itemProviderAtIndex:index].registeredTypeIdentifiers ?: @[ ];
@@ -239,6 +248,9 @@ static BOOL isImageType(NSString *type)
     if (_itemProviders == itemProviders || [_itemProviders isEqualToArray:itemProviders])
         return;
 
+    if (itemProviders.count != [_itemProviders count])
+        _preferredTypeIdentifiers = nil;
+
     _itemProviders = itemProviders;
     _changeCount++;
     _cachedTypeIdentifiers = nil;
@@ -247,7 +259,6 @@ static BOOL isImageType(NSString *type)
     [itemProviders enumerateObjectsUsingBlock:[typeToFileURLMaps] (UIItemProvider *, NSUInteger, BOOL *) {
         [typeToFileURLMaps addObject:@{ }];
     }];
-    _typeToFileURLMaps = typeToFileURLMaps;
 }
 
 - (NSInteger)numberOfItems
@@ -307,19 +318,32 @@ static BOOL isImageType(NSString *type)
         if (!provider)
             return;
 
-        NSData *data = [retainedSelf _preLoadedDataConformingToType:pasteboardType forItemProviderAtIndex:index];
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-        // FIXME: <rdar://problem/30451096> Adopt asynchronous UIItemProvider methods when retrieving data.
-        if (!data)
-            data = [provider copyDataRepresentationForTypeIdentifier:pasteboardType error:nil];
-#pragma clang diagnostic pop
-        if (data)
-            [values addObject:data];
+        if (NSData *loadedData = [retainedSelf _preLoadedDataConformingToType:pasteboardType forItemProviderAtIndex:index])
+            [values addObject:loadedData];
     }];
     return values.autorelease();
 }
 
+static Class classForTypeIdentifier(NSString *typeIdentifier)
+{
+    if (isColorType(typeIdentifier))
+        return [getUIColorClass() class];
+
+    if (isImageType(typeIdentifier))
+        return [getUIImageClass() class];
+
+    if (isURLType(typeIdentifier))
+        return [NSURL class];
+
+    if (isRichTextType(typeIdentifier))
+        return [NSAttributedString class];
+
+    if (isStringType(typeIdentifier))
+        return [NSString class];
+
+    return nil;
+}
+
 - (NSArray *)valuesForPasteboardType:(NSString *)pasteboardType inItemSet:(NSIndexSet *)itemSet
 {
     auto values = adoptNS([[NSMutableArray alloc] init]);
@@ -329,27 +353,14 @@ static BOOL isImageType(NSString *type)
         if (!provider)
             return;
 
-        Class readableClass;
-        if (isColorType(pasteboardType))
-            readableClass = [getUIColorClass() class];
-        else if (isImageType(pasteboardType))
-            readableClass = [getUIImageClass() class];
-        else if (isURLType(pasteboardType))
-            readableClass = [NSURL class];
-        else if (isRichTextType(pasteboardType))
-            readableClass = [NSAttributedString class];
-        else if (isStringType(pasteboardType))
-            readableClass = [NSString class];
-        else
+        Class readableClass = classForTypeIdentifier(pasteboardType);
+        if (!readableClass)
             return;
 
         id <UIItemProviderReading> readObject = nil;
         if (NSData *preloadedData = [retainedSelf _preLoadedDataConformingToType:pasteboardType forItemProviderAtIndex:index])
             readObject = [[readableClass alloc] initWithItemProviderData:preloadedData typeIdentifier:pasteboardType error:nil];
 
-        if (!readObject)
-            readObject = [retainedSelf _tryToCreateObjectOfClass:readableClass usingProvider:provider];
-
         if (readObject)
             [values addObject:readObject];
     }];
@@ -357,18 +368,6 @@ static BOOL isImageType(NSString *type)
     return values.autorelease();
 }
 
-- (id <UIItemProviderReading>)_tryToCreateObjectOfClass:(Class <UIItemProviderReading>)objectClass usingProvider:(UIItemProvider *)provider
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-    if (![provider canCreateObjectOfClass:objectClass])
-        return nil;
-
-    // FIXME: <rdar://problem/30451096> Adopt asynchronous UIItemProvider methods when retrieving data.
-    return [provider createObjectOfClass:objectClass error:nil];
-#pragma clang diagnostic pop
-}
-
 - (NSInteger)changeCount
 {
     return _changeCount;
@@ -416,18 +415,29 @@ static NSURL *temporaryFileURLForDataInteractionContent(NSString *fileExtension,
     auto changeCountBeforeLoading = _changeCount;
     auto typeToFileURLMaps = adoptNS([[NSMutableArray alloc] initWithCapacity:[_itemProviders count]]);
 
+    RetainPtr<NSArray> preferredTypeIdentifiers;
+    if ([_preferredTypeIdentifiers count] == [_itemProviders count])
+        preferredTypeIdentifiers = _preferredTypeIdentifiers;
+
     // First, figure out which item providers we want to try and load files from.
     auto itemProvidersWithFiles = adoptNS([[NSMutableArray alloc] init]);
     auto contentTypeIdentifiersToLoad = adoptNS([[NSMutableArray alloc] init]);
     auto indicesOfItemProvidersWithFiles = adoptNS([[NSMutableArray alloc] init]);
-    [_itemProviders enumerateObjectsUsingBlock:[itemProvidersWithFiles, contentTypeIdentifiersToLoad, indicesOfItemProvidersWithFiles, typeToFileURLMaps] (UIItemProvider *itemProvider, NSUInteger index, BOOL *) {
+    [_itemProviders enumerateObjectsUsingBlock:[preferredTypeIdentifiers, itemProvidersWithFiles, contentTypeIdentifiersToLoad, indicesOfItemProvidersWithFiles, typeToFileURLMaps] (UIItemProvider *itemProvider, NSUInteger index, BOOL *) {
         NSString *typeIdentifierOfContentToSave = nil;
-        for (NSString *identifier in itemProvider.registeredTypeIdentifiers) {
-            if (!UTTypeConformsTo((CFStringRef)identifier, kUTTypeContent))
-                continue;
 
-            typeIdentifierOfContentToSave = identifier;
-            break;
+        if (preferredTypeIdentifiers && [itemProvider.registeredTypeIdentifiers containsObject:[preferredTypeIdentifiers objectAtIndex:index]])
+            typeIdentifierOfContentToSave = [preferredTypeIdentifiers objectAtIndex:index];
+
+        if (!typeIdentifierOfContentToSave) {
+            // Fall back to the first "public.content"-conformant type identifier.
+            for (NSString *identifier in itemProvider.registeredTypeIdentifiers) {
+                if (!UTTypeConformsTo((CFStringRef)identifier, kUTTypeContent))
+                    continue;
+
+                typeIdentifierOfContentToSave = identifier;
+                break;
+            }
         }
 
         if (typeIdentifierOfContentToSave) {
index fb4829f..df968cb 100644 (file)
@@ -285,6 +285,52 @@ String DragData::asURL(FilenameConversionPolicy, String* title) const
     return String();        
 }
 
+#if ENABLE(DATA_INTERACTION)
+
+void DragData::updatePreferredTypeIdentifiers(const Vector<String>& supportedTypesVector) const
+{
+    NSMutableSet *supportedTypes = [NSMutableSet setWithCapacity:supportedTypesVector.size()];
+    for (auto& supportedType : supportedTypesVector)
+        [supportedTypes addObject:supportedType];
+
+    // Match UIItemProvider behavior by performing two-pass UTI matching.
+    Vector<String> bestTypeIdentifiers;
+    auto& strategy = *platformStrategies()->pasteboardStrategy();
+    uint64_t itemCount = strategy.getPasteboardItemsCount(m_pasteboardName);
+    for (uint64_t itemIndex = 0; itemIndex < itemCount; ++itemIndex) {
+        Vector<String> typeIdentifiers;
+        strategy.getTypesByFidelityForItemAtIndex(typeIdentifiers, itemIndex, m_pasteboardName);
+
+        String bestTypeIdentifier = emptyString();
+        // In the first pass, look for the highest fidelity UTI that exactly matches one of the supported UTIs.
+        for (auto& type : typeIdentifiers) {
+            if ([supportedTypes containsObject:(NSString *)type]) {
+                bestTypeIdentifier = type;
+                break;
+            }
+        }
+
+        // In the second pass, look for the highest fidelity UTI that conforms to one of the supported UTIs.
+        if (bestTypeIdentifier.isEmpty()) {
+            for (auto& type : typeIdentifiers) {
+                for (NSString *supportedType in supportedTypes) {
+                    if (UTTypeConformsTo(type.createCFString().autorelease(), (CFStringRef)supportedType)) {
+                        bestTypeIdentifier = type;
+                        break;
+                    }
+                }
+                if (!bestTypeIdentifier.isEmpty())
+                    break;
+            }
+        }
+        bestTypeIdentifiers.append(bestTypeIdentifier);
+    }
+
+    strategy.updatePreferredTypeIdentifiers(bestTypeIdentifiers, m_pasteboardName);
+}
+
+#endif
+
 } // namespace WebCore
 
 #endif // ENABLE(DRAG_SUPPORT)
index 40577f3..57e2ad1 100644 (file)
@@ -1,3 +1,17 @@
+2017-04-26  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        WebItemProviderPasteboard should not synchronously load provided data
+        https://bugs.webkit.org/show_bug.cgi?id=171341
+        <rdar://problem/31614010>
+
+        Reviewed by Tim Horton.
+
+        Adds client-layer plumbing for updatePreferredTypeIdentifiers. See WebCore ChangeLog for more details.
+
+        * WebCoreSupport/WebPlatformStrategies.h:
+        * WebCoreSupport/WebPlatformStrategies.mm:
+        (WebPlatformStrategies::updatePreferredTypeIdentifiers):
+
 2017-04-26  Zalan Bujtas  <zalan@apple.com>
 
         RTL: recent searches popover is displayed in incorrect location
index da4ec47..5e9238a 100644 (file)
@@ -67,6 +67,7 @@ private:
     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;
     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
+    void updatePreferredTypeIdentifiers(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;
index 74bc7af..fe3b9eb 100644 (file)
@@ -216,6 +216,11 @@ int WebPlatformStrategies::getPasteboardItemsCount(const String& pasteboardName)
     return PlatformPasteboard(pasteboardName).count();
 }
 
+void WebPlatformStrategies::updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
+{
+    PlatformPasteboard(pasteboardName).updatePreferredTypeIdentifiers(identifiers);
+}
+
 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::readBufferFromPasteboard(int index, const String& type, const String& pasteboardName)
 {
     return PlatformPasteboard(pasteboardName).readBuffer(index, type);
index b13a673..eda7e89 100644 (file)
@@ -1,3 +1,23 @@
+2017-04-26  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        WebItemProviderPasteboard should not synchronously load provided data
+        https://bugs.webkit.org/show_bug.cgi?id=171341
+        <rdar://problem/31614010>
+
+        Reviewed by Tim Horton.
+
+        Adds plumbing for updatePreferredTypeIdentifiers through the WebPasteboardProxy. This allows the web process to
+        signal to the UI process what UTIs the current drop target should accept and load. See WebCore ChangeLog for more
+        details.
+
+        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
+        (WebKit::WebPasteboardProxy::updatePreferredTypeIdentifiers):
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
+        (WebKit::WebPlatformStrategies::updatePreferredTypeIdentifiers):
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
+
 2017-04-26  Youenn Fablet  <youenn@apple.com>
 
         Unauthenticated CORS preflight requests should not use client certificates
index 9cc1b87..9ff056f 100644 (file)
@@ -198,6 +198,11 @@ void WebPasteboardProxy::getFilenamesForDataInteraction(const String& pasteboard
     filenames = PlatformPasteboard(pasteboardName).filenamesForDataInteraction();
 }
 
+void WebPasteboardProxy::updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
+{
+    PlatformPasteboard(pasteboardName).updatePreferredTypeIdentifiers(identifiers);
+}
+
 #endif
 
 } // namespace WebKit
index b5a531a..44e8365 100644 (file)
@@ -79,6 +79,7 @@ private:
     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 getFilenamesForDataInteraction(const String& pasteboardName, Vector<String>& filenames);
+    void updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName);
 #endif
 #if PLATFORM(COCOA)
     void getNumberOfFiles(const String& pasteboardName, uint64_t& numberOfFiles);
index 241425d..766bc12 100644 (file)
@@ -31,6 +31,7 @@ messages -> WebPasteboardProxy {
     ReadBufferFromPasteboard(uint64_t index, String pasteboardType, String pasteboardName) -> (WebKit::SharedMemory::Handle handle, uint64_t size)
     GetPasteboardItemsCount(String pasteboardName) -> (uint64_t itemsCount)
     GetFilenamesForDataInteraction(String pasteboardName) -> (Vector<String> filenames)
+    UpdatePreferredTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
     GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types)
 #endif
 
index 24862bd..823290d 100644 (file)
@@ -324,6 +324,11 @@ void WebPlatformStrategies::getFilenamesForDataInteraction(Vector<String>& filen
     WebProcess::singleton().parentProcessConnection()->sendSync(Messages::WebPasteboardProxy::GetFilenamesForDataInteraction(pasteboardName), Messages::WebPasteboardProxy::GetFilenamesForDataInteraction::Reply(filenames), 0);
 }
 
+void WebPlatformStrategies::updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
+{
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::UpdatePreferredTypeIdentifiers(identifiers, pasteboardName), 0);
+}
+
 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName)
 {
     SharedMemory::Handle handle;
index c80fafc..41938ed 100644 (file)
@@ -68,6 +68,7 @@ private:
     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;
     void getFilenamesForDataInteraction(Vector<String>& filenames, const String& pasteboardName) override;
+    void updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName) override;
     void getTypesByFidelityForItemAtIndex(Vector<String>& types, uint64_t index, const String& pasteboardName) override;
 #endif
 #if PLATFORM(COCOA)