Using -[WebItemProviderPasteboard setItemProviders:] to swap out item providers befor...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Jun 2017 18:11:52 +0000 (18:11 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 15 Jun 2017 18:11:52 +0000 (18:11 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173338
<rdar://problem/32777720>

Reviewed by Tim Horton.

Source/WebCore:

Currently, replacing the list of UIItemProviders right before a drop is handled results in
WebItemProviderPasteboard failing to load non-"public.content"-conformant items. This is because DragController
computes and sends to the UI process a list of UTIs to load (preferredTypeIdentifiers: one type identifier for
each item provider in WebItemProviderPasteboard). However, if the list of item providers changes immediately
before a drop is performed, WebItemProviderPasteboard will get into an inconsistent state where it has a
different number of preferred type identifiers to load than available item providers. This causes
WebItemProviderPasteboard to fail when choosing what type identifiers to load from each item provider.

To fix this, we instead have the web process propagate a list of supported type identifiers to the UI process,
which is a property of only the drop destination rather than both the destination and item providers. When
performing a drop, we then use the current item providers on WebItemProviderPasteboard to consult this list of
supported type identifiers to resolve our list of preferred type identifiers to load.

Globally renames updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers.

Tests:
DataInteractionTests.ExternalSourceOverrideDropFileUpload
DataInteractionTests.ExternalSourceOverrideDropInsertURL

* page/DragController.cpp:
(WebCore::DragController::dragEnteredOrUpdated):
(WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod):
(WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod): Deleted.
* page/DragController.h:
* page/mac/DragControllerMac.mm:
(WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod):
(WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod): Deleted.
* platform/DragData.h:
* platform/PasteboardStrategy.h:
* platform/PlatformPasteboard.h:
* platform/ios/AbstractPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::PlatformPasteboard::updateSupportedTypeIdentifiers):
(WebCore::PlatformPasteboard::updatePreferredTypeIdentifiers): Deleted.
* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard init]):
(-[WebItemProviderPasteboard updateSupportedTypeIdentifiers:]):
(-[WebItemProviderPasteboard setItemProviders:]):
(-[WebItemProviderPasteboard typeIsAppropriateForSupportedTypes:]):
(-[WebItemProviderPasteboard typeIdentifierToLoadForRegisteredTypeIdentfiers:]):

Add logic to resolve preferred type identifiers from an item providers list of registered type identifiers.
This formerly existed on DragData.

(-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
(-[WebItemProviderPasteboard updatePreferredTypeIdentifiers:]): Deleted.
* platform/mac/DragDataMac.mm:

Remove preferred type identifier resolution logic from DragData.

(WebCore::typeIsAppropriateForSupportedTypes): Deleted.
(WebCore::DragData::updatePreferredTypeIdentifiers): Deleted.

Source/WebKit/mac:

Rename updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers.

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

Source/WebKit2:

Rename updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers. Also, introduce
_webView:willPerformDropWithSession: as SPI on WKUIDelegate.

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

Tools:

Adds new unit tests to ensure that -_webView:willPerformDropWithSession: can be used to filter out drag items
used by WebKit when handling a drop. These tests ensure that WebItemProviderPasteboard is still able to handle
these remaining items on drop.

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

Add -overridePerformDropBlock, which can be set to provide custom handling of dropped items.

(-[DataInteractionSimulator _webView:willPerformDropWithSession:]):

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

25 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/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/API/Cocoa/WKUIDelegatePrivate.h
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
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm
Tools/TestWebKitAPI/ios/DataInteractionSimulator.h
Tools/TestWebKitAPI/ios/DataInteractionSimulator.mm

index 0b27329..582ee5f 100644 (file)
@@ -1,3 +1,64 @@
+2017-06-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Using -[WebItemProviderPasteboard setItemProviders:] to swap out item providers before a drop breaks item provider loading
+        https://bugs.webkit.org/show_bug.cgi?id=173338
+        <rdar://problem/32777720>
+
+        Reviewed by Tim Horton.
+
+        Currently, replacing the list of UIItemProviders right before a drop is handled results in
+        WebItemProviderPasteboard failing to load non-"public.content"-conformant items. This is because DragController
+        computes and sends to the UI process a list of UTIs to load (preferredTypeIdentifiers: one type identifier for
+        each item provider in WebItemProviderPasteboard). However, if the list of item providers changes immediately
+        before a drop is performed, WebItemProviderPasteboard will get into an inconsistent state where it has a
+        different number of preferred type identifiers to load than available item providers. This causes
+        WebItemProviderPasteboard to fail when choosing what type identifiers to load from each item provider.
+
+        To fix this, we instead have the web process propagate a list of supported type identifiers to the UI process,
+        which is a property of only the drop destination rather than both the destination and item providers. When
+        performing a drop, we then use the current item providers on WebItemProviderPasteboard to consult this list of
+        supported type identifiers to resolve our list of preferred type identifiers to load.
+
+        Globally renames updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers.
+
+        Tests:
+        DataInteractionTests.ExternalSourceOverrideDropFileUpload
+        DataInteractionTests.ExternalSourceOverrideDropInsertURL
+
+        * page/DragController.cpp:
+        (WebCore::DragController::dragEnteredOrUpdated):
+        (WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod):
+        (WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod): Deleted.
+        * page/DragController.h:
+        * page/mac/DragControllerMac.mm:
+        (WebCore::DragController::updateSupportedTypeIdentifiersForDragHandlingMethod):
+        (WebCore::DragController::updatePreferredTypeIdentifiersForDragHandlingMethod): Deleted.
+        * platform/DragData.h:
+        * platform/PasteboardStrategy.h:
+        * platform/PlatformPasteboard.h:
+        * platform/ios/AbstractPasteboard.h:
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::PlatformPasteboard::updateSupportedTypeIdentifiers):
+        (WebCore::PlatformPasteboard::updatePreferredTypeIdentifiers): Deleted.
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderPasteboard init]):
+        (-[WebItemProviderPasteboard updateSupportedTypeIdentifiers:]):
+        (-[WebItemProviderPasteboard setItemProviders:]):
+        (-[WebItemProviderPasteboard typeIsAppropriateForSupportedTypes:]):
+        (-[WebItemProviderPasteboard typeIdentifierToLoadForRegisteredTypeIdentfiers:]):
+
+        Add logic to resolve preferred type identifiers from an item providers list of registered type identifiers.
+        This formerly existed on DragData.
+
+        (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
+        (-[WebItemProviderPasteboard updatePreferredTypeIdentifiers:]): Deleted.
+        * platform/mac/DragDataMac.mm:
+
+        Remove preferred type identifier resolution logic from DragData.
+
+        (WebCore::typeIsAppropriateForSupportedTypes): Deleted.
+        (WebCore::DragData::updatePreferredTypeIdentifiers): Deleted.
+
 2017-06-15  Sam Weinig  <sam@webkit.org>
 
         [WebIDL] Replace general inclusion of JSDOMConvert.h with inclusion of individual converter files to reduce unnecessary inclusion
index cbe103d..48183f9 100644 (file)
@@ -309,7 +309,6 @@ 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)?
@@ -324,7 +323,7 @@ DragOperation DragController::dragEnteredOrUpdated(const DragData& dragData)
             m_dragHandlingMethod = DragHandlingMethod::PageLoad;
     }
 
-    updatePreferredTypeIdentifiersForDragHandlingMethod(m_dragHandlingMethod, dragData);
+    updateSupportedTypeIdentifiersForDragHandlingMethod(m_dragHandlingMethod, dragData);
     return dragOperation;
 }
 
@@ -365,7 +364,7 @@ static Element* elementUnderMouse(Document* documentUnderMouse, const IntPoint&
 
 #if !ENABLE(DATA_INTERACTION)
 
-void DragController::updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const
+void DragController::updateSupportedTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const
 {
 }
 
index eade6c6..2df6f40 100644 (file)
@@ -99,7 +99,7 @@ struct DragState;
         static const float DragImageAlpha;
 
     private:
-        void updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const;
+        void updateSupportedTypeIdentifiersForDragHandlingMethod(DragHandlingMethod, const DragData&) const;
         bool dispatchTextInputEventFor(Frame*, const DragData&);
         bool canProcessDrag(const DragData&);
         bool concludeEditDrag(const DragData&);
@@ -145,7 +145,6 @@ struct DragState;
 
         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 cb09a22..b812188 100644 (file)
@@ -42,6 +42,8 @@
 #import "MainFrame.h"
 #import "Page.h"
 #import "Pasteboard.h"
+#import "PasteboardStrategy.h"
+#import "PlatformStrategies.h"
 #import "Range.h"
 
 #if ENABLE(DATA_INTERACTION)
@@ -104,7 +106,7 @@ void DragController::cleanupAfterSystemDrag()
 
 #if ENABLE(DATA_INTERACTION)
 
-void DragController::updatePreferredTypeIdentifiersForDragHandlingMethod(DragHandlingMethod dragHandlingMethod, const DragData& dragData) const
+void DragController::updateSupportedTypeIdentifiersForDragHandlingMethod(DragHandlingMethod dragHandlingMethod, const DragData& dragData) const
 {
     Vector<String> supportedTypes;
     switch (dragHandlingMethod) {
@@ -123,7 +125,7 @@ void DragController::updatePreferredTypeIdentifiersForDragHandlingMethod(DragHan
         supportedTypes.append(kUTTypeContent);
         break;
     }
-    dragData.updatePreferredTypeIdentifiers(supportedTypes);
+    platformStrategies()->pasteboardStrategy()->updateSupportedTypeIdentifiers(supportedTypes, dragData.pasteboardName());
 }
 
 #endif
index 50ceb86..acf322c 100644 (file)
@@ -114,9 +114,6 @@ public:
     bool containsURLTypeIdentifier() const;
     bool containsPromise() const;
 #endif
-#if ENABLE(DATA_INTERACTION)
-    void updatePreferredTypeIdentifiers(const Vector<String>& supportedTypes) const;
-#endif
 
 #if PLATFORM(GTK)
 
index 3c6da6c..9bf279e 100644 (file)
@@ -52,7 +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 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)
 #if PLATFORM(COCOA)
index 23f6f30..afda155 100644 (file)
@@ -61,7 +61,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);
+    WEBCORE_EXPORT void updateSupportedTypeIdentifiers(const Vector<String>& types);
 #endif
     WEBCORE_EXPORT static String uniqueName();
 
index e1c2c2c..b744fe2 100644 (file)
@@ -45,7 +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;
+- (void)updateSupportedTypeIdentifiers:(NSArray<NSString *> *)types;
 
 @end
 
index 76ca987..5b87ed6 100644 (file)
@@ -456,16 +456,16 @@ URL PlatformPasteboard::readURL(int index, const String& type, String& title)
     return (NSURL *)value;
 }
 
-void PlatformPasteboard::updatePreferredTypeIdentifiers(const Vector<String>& types)
+void PlatformPasteboard::updateSupportedTypeIdentifiers(const Vector<String>& types)
 {
-    if (![m_pasteboard respondsToSelector:@selector(updatePreferredTypeIdentifiers:)])
+    if (![m_pasteboard respondsToSelector:@selector(updateSupportedTypeIdentifiers:)])
         return;
 
     NSMutableArray *typesArray = [NSMutableArray arrayWithCapacity:types.size()];
     for (auto type : types)
         [typesArray addObject:(NSString *)type];
 
-    [m_pasteboard updatePreferredTypeIdentifiers:typesArray];
+    [m_pasteboard updateSupportedTypeIdentifiers:typesArray];
 }
 
 }
index 0eb98ac..3054d0b 100644 (file)
@@ -156,7 +156,7 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
     RetainPtr<NSArray> _itemProviders;
     RetainPtr<NSArray> _cachedTypeIdentifiers;
     RetainPtr<NSArray> _typeToFileURLMaps;
-    RetainPtr<NSArray> _preferredTypeIdentifiers;
+    RetainPtr<NSArray> _supportedTypeIdentifiers;
     RetainPtr<NSArray> _registrationInfoLists;
 }
 
@@ -177,16 +177,15 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
         _changeCount = 0;
         _pendingOperationCount = 0;
         _typeToFileURLMaps = adoptNS([[NSArray alloc] init]);
-        _preferredTypeIdentifiers = nil;
+        _supportedTypeIdentifiers = nil;
         _registrationInfoLists = nil;
     }
     return self;
 }
 
-- (void)updatePreferredTypeIdentifiers:(NSArray<NSString *> *)types
+- (void)updateSupportedTypeIdentifiers:(NSArray<NSString *> *)types
 {
-    if ([_itemProviders count] == types.count)
-        _preferredTypeIdentifiers = types;
+    _supportedTypeIdentifiers = types;
 }
 
 - (NSArray<NSString *> *)pasteboardTypesByFidelityForItemAtIndex:(NSUInteger)index
@@ -225,9 +224,6 @@ typedef NSDictionary<NSString *, NSURL *> TypeToFileURLMap;
     if (_itemProviders == itemProviders || [_itemProviders isEqualToArray:itemProviders])
         return;
 
-    if (itemProviders.count != [_itemProviders count])
-        _preferredTypeIdentifiers = nil;
-
     _itemProviders = itemProviders;
     _changeCount++;
     _cachedTypeIdentifiers = nil;
@@ -409,6 +405,29 @@ static NSURL *temporaryFileURLForDataInteractionContent(NSURL *url, NSString *su
     return [NSURL fileURLWithPath:[temporaryDataInteractionDirectory stringByAppendingPathComponent:suggestedName ?: url.lastPathComponent]];
 }
 
+- (BOOL)typeIsAppropriateForSupportedTypes:(NSString *)type
+{
+    // A type is considered appropriate to load if it conforms to one or more supported types.
+    for (NSString *supportedTypeIdentifier in _supportedTypeIdentifiers.get()) {
+        if (UTTypeConformsTo((CFStringRef)type, (CFStringRef)supportedTypeIdentifier))
+            return YES;
+    }
+    return NO;
+}
+
+- (NSString *)typeIdentifierToLoadForRegisteredTypeIdentfiers:(NSArray<NSString *> *)registeredTypeIdentifiers
+{
+    NSString *highestFidelityContentType = nil;
+    for (NSString *registeredTypeIdentifier in registeredTypeIdentifiers) {
+        if ([self typeIsAppropriateForSupportedTypes:registeredTypeIdentifier])
+            return registeredTypeIdentifier;
+
+        if (!highestFidelityContentType && UTTypeConformsTo((CFStringRef)registeredTypeIdentifier, kUTTypeContent))
+            highestFidelityContentType = registeredTypeIdentifier;
+    }
+    return highestFidelityContentType;
+}
+
 - (void)doAfterLoadingProvidedContentIntoFileURLs:(WebItemProviderFileLoadBlock)action
 {
     [self doAfterLoadingProvidedContentIntoFileURLs:action synchronousTimeout:0];
@@ -419,41 +438,22 @@ static NSURL *temporaryFileURLForDataInteractionContent(NSURL *url, NSString *su
     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:[preferredTypeIdentifiers, itemProvidersWithFiles, contentTypeIdentifiersToLoad, indicesOfItemProvidersWithFiles, typeToFileURLMaps] (UIItemProvider *itemProvider, NSUInteger index, BOOL *) {
-        NSString *typeIdentifierOfContentToSave = nil;
-
-        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;
-            }
+    auto itemProvidersToLoad = adoptNS([[NSMutableArray alloc] init]);
+    auto typeIdentifiersToLoad = adoptNS([[NSMutableArray alloc] init]);
+    auto indicesOfitemProvidersToLoad = adoptNS([[NSMutableArray alloc] init]);
+    RetainPtr<WebItemProviderPasteboard> protectedSelf = self;
+    [_itemProviders enumerateObjectsUsingBlock:[protectedSelf, itemProvidersToLoad, typeIdentifiersToLoad, indicesOfitemProvidersToLoad, typeToFileURLMaps] (UIItemProvider *itemProvider, NSUInteger index, BOOL *) {
+        NSString *typeIdentifierToLoad = [protectedSelf typeIdentifierToLoadForRegisteredTypeIdentfiers:itemProvider.registeredTypeIdentifiers];
+        if (typeIdentifierToLoad) {
+            [itemProvidersToLoad addObject:itemProvider];
+            [typeIdentifiersToLoad addObject:typeIdentifierToLoad];
+            [indicesOfitemProvidersToLoad addObject:@(index)];
         }
-
-        if (typeIdentifierOfContentToSave) {
-            [itemProvidersWithFiles addObject:itemProvider];
-            [contentTypeIdentifiersToLoad addObject:typeIdentifierOfContentToSave];
-            [indicesOfItemProvidersWithFiles addObject:@(index)];
-        }
-
         [typeToFileURLMaps addObject:@{ }];
     }];
 
-    if (![itemProvidersWithFiles count]) {
+    if (![itemProvidersToLoad count]) {
         action(@[ ]);
         return;
     }
@@ -461,10 +461,10 @@ static NSURL *temporaryFileURLForDataInteractionContent(NSURL *url, NSString *su
     auto setFileURLsLock = adoptNS([[NSLock alloc] init]);
     auto synchronousFileLoadingGroup = adoptOSObject(dispatch_group_create());
     auto fileLoadingGroup = adoptOSObject(dispatch_group_create());
-    for (NSUInteger index = 0; index < [itemProvidersWithFiles count]; ++index) {
-        RetainPtr<UIItemProvider> itemProvider = [itemProvidersWithFiles objectAtIndex:index];
-        RetainPtr<NSString> typeIdentifier = [contentTypeIdentifiersToLoad objectAtIndex:index];
-        NSUInteger indexInItemProviderArray = [[indicesOfItemProvidersWithFiles objectAtIndex:index] unsignedIntegerValue];
+    for (NSUInteger index = 0; index < [itemProvidersToLoad count]; ++index) {
+        RetainPtr<UIItemProvider> itemProvider = [itemProvidersToLoad objectAtIndex:index];
+        RetainPtr<NSString> typeIdentifier = [typeIdentifiersToLoad objectAtIndex:index];
+        NSUInteger indexInItemProviderArray = [[indicesOfitemProvidersToLoad objectAtIndex:index] unsignedIntegerValue];
         RetainPtr<NSString> suggestedName = [itemProvider suggestedName];
         dispatch_group_enter(fileLoadingGroup.get());
         dispatch_group_enter(synchronousFileLoadingGroup.get());
index a49e134..20d129d 100644 (file)
@@ -292,43 +292,6 @@ String DragData::asURL(FilenameConversionPolicy, String* title) const
     return String();        
 }
 
-#if ENABLE(DATA_INTERACTION)
-
-static bool typeIsAppropriateForSupportedTypes(const String& type, const Vector<String>& supportedTypes)
-{
-    CFStringRef cfType = type.createCFString().autorelease();
-    for (auto supportedType : supportedTypes) {
-        if (UTTypeConformsTo(cfType, supportedType.createCFString().get()))
-            return true;
-    }
-    return false;
-}
-
-void DragData::updatePreferredTypeIdentifiers(const Vector<String>& supportedTypes) const
-{
-    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();
-        for (auto& type : typeIdentifiers) {
-            if (!typeIsAppropriateForSupportedTypes(type, supportedTypes))
-                continue;
-
-            bestTypeIdentifier = type;
-            break;
-        }
-        bestTypeIdentifiers.append(bestTypeIdentifier);
-    }
-
-    strategy.updatePreferredTypeIdentifiers(bestTypeIdentifiers, m_pasteboardName);
-}
-
-#endif
-
 } // namespace WebCore
 
 #endif // ENABLE(DRAG_SUPPORT)
index 45956f5..7ec6777 100644 (file)
@@ -1,3 +1,18 @@
+2017-06-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Using -[WebItemProviderPasteboard setItemProviders:] to swap out item providers before a drop breaks item provider loading
+        https://bugs.webkit.org/show_bug.cgi?id=173338
+        <rdar://problem/32777720>
+
+        Reviewed by Tim Horton.
+
+        Rename updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers.
+
+        * WebCoreSupport/WebPlatformStrategies.h:
+        * WebCoreSupport/WebPlatformStrategies.mm:
+        (WebPlatformStrategies::updateSupportedTypeIdentifiers):
+        (WebPlatformStrategies::updatePreferredTypeIdentifiers): Deleted.
+
 2017-06-13  Daniel Bates  <dabates@apple.com>
 
         Implement W3C Secure Contexts Draft Specification
index 5e9238a..ab264a6 100644 (file)
@@ -67,7 +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 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;
index fe3b9eb..5f0dbef 100644 (file)
@@ -216,9 +216,9 @@ int WebPlatformStrategies::getPasteboardItemsCount(const String& pasteboardName)
     return PlatformPasteboard(pasteboardName).count();
 }
 
-void WebPlatformStrategies::updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
+void WebPlatformStrategies::updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
 {
-    PlatformPasteboard(pasteboardName).updatePreferredTypeIdentifiers(identifiers);
+    PlatformPasteboard(pasteboardName).updateSupportedTypeIdentifiers(identifiers);
 }
 
 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::readBufferFromPasteboard(int index, const String& type, const String& pasteboardName)
index eb16371..dd4d56b 100644 (file)
@@ -1,3 +1,25 @@
+2017-06-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Using -[WebItemProviderPasteboard setItemProviders:] to swap out item providers before a drop breaks item provider loading
+        https://bugs.webkit.org/show_bug.cgi?id=173338
+        <rdar://problem/32777720>
+
+        Reviewed by Tim Horton.
+
+        Rename updatePreferredTypeIdentifiers to updateSupportedTypeIdentifiers. Also, introduce
+        _webView:willPerformDropWithSession: as SPI on WKUIDelegate.
+
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+        * UIProcess/Cocoa/WebPasteboardProxyCocoa.mm:
+        (WebKit::WebPasteboardProxy::updateSupportedTypeIdentifiers):
+        (WebKit::WebPasteboardProxy::updatePreferredTypeIdentifiers): Deleted.
+        * UIProcess/WebPasteboardProxy.h:
+        * UIProcess/WebPasteboardProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.cpp:
+        (WebKit::WebPlatformStrategies::updateSupportedTypeIdentifiers):
+        (WebKit::WebPlatformStrategies::updatePreferredTypeIdentifiers): Deleted.
+        * WebProcess/WebCoreSupport/WebPlatformStrategies.h:
+
 2017-06-15  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Cleanup headers includes in GTK+ API files
index 9dd1a66..07982cc 100644 (file)
@@ -44,6 +44,7 @@
 @class UIDragItem;
 @class UITargetedDragPreview;
 @protocol UIDragSession;
+@protocol UIDropSession;
 #endif
 
 @protocol WKUIDelegatePrivate <WKUIDelegate>
@@ -112,6 +113,7 @@ struct UIEdgeInsets;
 #if TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
 - (UITargetedDragPreview *)_webView:(WKWebView *)webView previewForLiftingItem:(UIDragItem *)item session:(id <UIDragSession>)session WK_API_AVAILABLE(ios(WK_IOS_TBA));
 - (UITargetedDragPreview *)_webView:(WKWebView *)webView previewForCancellingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview WK_API_AVAILABLE(ios(WK_IOS_TBA));
+- (NSArray<UIDragItem *> *)_webView:(WKWebView *)webView willPerformDropWithSession:(id <UIDropSession>)session WK_API_AVAILABLE(ios(WK_IOS_TBA));
 #endif
 - (void)_webView:(WKWebView *)webView didChangeSafeAreaShouldAffectObscuredInsets:(BOOL)safeAreaShouldAffectObscuredInsets WK_API_AVAILABLE(ios(WK_IOS_TBA));
 #else
index 9ff056f..51ca16b 100644 (file)
@@ -198,9 +198,9 @@ void WebPasteboardProxy::getFilenamesForDataInteraction(const String& pasteboard
     filenames = PlatformPasteboard(pasteboardName).filenamesForDataInteraction();
 }
 
-void WebPasteboardProxy::updatePreferredTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
+void WebPasteboardProxy::updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
 {
-    PlatformPasteboard(pasteboardName).updatePreferredTypeIdentifiers(identifiers);
+    PlatformPasteboard(pasteboardName).updateSupportedTypeIdentifiers(identifiers);
 }
 
 #endif
index 9bb6d54..8d76890 100644 (file)
@@ -79,7 +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);
+    void updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName);
 #endif
 #if PLATFORM(COCOA)
     void getNumberOfFiles(const String& pasteboardName, uint64_t& numberOfFiles);
index 4012ad5..c388293 100644 (file)
@@ -31,7 +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)
+    UpdateSupportedTypeIdentifiers(Vector<String> identifiers, String pasteboardName)
     GetPasteboardTypesByFidelityForItemAtIndex(uint64_t index, String pasteboardName) -> (Vector<String> types)
 #endif
 
index 1aa2d8b..8214082 100644 (file)
@@ -324,9 +324,9 @@ 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)
+void WebPlatformStrategies::updateSupportedTypeIdentifiers(const Vector<String>& identifiers, const String& pasteboardName)
 {
-    WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::UpdatePreferredTypeIdentifiers(identifiers, pasteboardName), 0);
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebPasteboardProxy::UpdateSupportedTypeIdentifiers(identifiers, pasteboardName), 0);
 }
 
 RefPtr<WebCore::SharedBuffer> WebPlatformStrategies::readBufferFromPasteboard(int index, const String& pasteboardType, const String& pasteboardName)
index 72dcf9f..f78a731 100644 (file)
@@ -68,7 +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 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)
index 2d7c0b4..1cf5097 100644 (file)
@@ -1,3 +1,24 @@
+2017-06-15  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        Using -[WebItemProviderPasteboard setItemProviders:] to swap out item providers before a drop breaks item provider loading
+        https://bugs.webkit.org/show_bug.cgi?id=173338
+        <rdar://problem/32777720>
+
+        Reviewed by Tim Horton.
+
+        Adds new unit tests to ensure that -_webView:willPerformDropWithSession: can be used to filter out drag items
+        used by WebKit when handling a drop. These tests ensure that WebItemProviderPasteboard is still able to handle
+        these remaining items on drop.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/ios/DataInteractionSimulator.h:
+        * TestWebKitAPI/ios/DataInteractionSimulator.mm:
+
+        Add -overridePerformDropBlock, which can be set to provide custom handling of dropped items.
+
+        (-[DataInteractionSimulator _webView:willPerformDropWithSession:]):
+
 2017-06-15  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] Crash in accessibility layout test.
index b41fd99..39619bf 100644 (file)
@@ -686,6 +686,64 @@ TEST(DataInteractionTests, ExternalSourceFileURL)
     EXPECT_WK_STREQ("Hello world\nfile:///some/file/that/is/not/real", [webView stringByEvaluatingJavaScript:@"document.body.innerText"]);
 }
 
+TEST(DataInteractionTests, ExternalSourceOverrideDropFileUpload)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"file-uploading"];
+
+    auto simulatedImageItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *imageData = UIImageJPEGRepresentation(testIconImage(), 0.5);
+    [simulatedImageItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG withData:imageData];
+
+    auto simulatedHTMLItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    NSData *firstHTMLData = [@"<body contenteditable></body>" dataUsingEncoding:NSUTF8StringEncoding];
+    [simulatedHTMLItemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeHTML withData:firstHTMLData];
+
+    auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
+    {
+        EXPECT_EQ(2UL, session.items.count);
+        UIDragItem *firstItem = session.items[0];
+        UIDragItem *secondItem = session.items[1];
+        EXPECT_TRUE([firstItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeJPEG ]]);
+        EXPECT_TRUE([secondItem.itemProvider.registeredTypeIdentifiers isEqual:@[ (NSString *)kUTTypeHTML ]]);
+        return @[ secondItem ];
+    }];
+    [dataInteractionSimulator setExternalItemProviders:@[ simulatedImageItemProvider.get(), simulatedHTMLItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(200, 300) to:CGPointMake(100, 300)];
+
+    NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
+    EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
+}
+
+TEST(DataInteractionTests, ExternalSourceOverrideDropInsertURL)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"autofocus-contenteditable"];
+    [webView stringByEvaluatingJavaScript:@"getSelection().removeAllRanges()"];
+
+    auto dataInteractionSimulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+    [dataInteractionSimulator setOverridePerformDropBlock:^NSArray<UIDragItem *> *(id <UIDropSession> session)
+    {
+        NSMutableArray<UIDragItem *> *allowedItems = [NSMutableArray array];
+        for (UIDragItem *item in session.items) {
+            if ([item.itemProvider.registeredTypeIdentifiers containsObject:(NSString *)kUTTypeURL])
+                [allowedItems addObject:item];
+        }
+        EXPECT_EQ(1UL, allowedItems.count);
+        return allowedItems;
+    }];
+
+    auto firstItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [firstItemProvider registerObject:@"This is a string." visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+    auto secondItemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [secondItemProvider registerObject:[NSURL URLWithString:@"https://webkit.org/"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+    [dataInteractionSimulator setExternalItemProviders:@[ firstItemProvider.get(), secondItemProvider.get() ]];
+    [dataInteractionSimulator runFrom:CGPointMake(300, 400) to:CGPointMake(100, 300)];
+
+    EXPECT_WK_STREQ("https://webkit.org/", [webView stringByEvaluatingJavaScript:@"editor.textContent"]);
+}
+
 TEST(DataInteractionTests, OverrideDataInteractionOperation)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
index 69e4f96..1808aa0 100644 (file)
@@ -76,6 +76,7 @@ typedef NS_ENUM(NSInteger, DataInteractionPhase) {
 @property (nonatomic) BOOL shouldEnsureUIApplication;
 @property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock;
 @property (nonatomic) BlockPtr<NSArray *(UIItemProvider *, NSArray *, NSDictionary *)> convertItemProvidersBlock;
+@property (nonatomic) BlockPtr<NSArray *(id <UIDropSession>)> overridePerformDropBlock;
 @property (nonatomic, strong) NSArray *externalItemProviders;
 @property (nonatomic) BlockPtr<NSUInteger(NSUInteger, id)> overrideDataInteractionOperationBlock;
 @property (nonatomic) BlockPtr<void(BOOL, NSArray *)> dataInteractionOperationCompletionBlock;
index 83014a8..7090f7b 100644 (file)
@@ -326,6 +326,11 @@ static NSArray *dataInteractionEventNames()
     return self.showCustomActionSheetBlock(element);
 }
 
+- (NSArray<UIDragItem *> *)_webView:(WKWebView *)webView willPerformDropWithSession:(id <UIDropSession>)session
+{
+    return self.overridePerformDropBlock ? self.overridePerformDropBlock(session) : session.items;
+}
+
 #pragma mark - _WKInputDelegate
 
 - (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info