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 0b27329c78d2af92a139cd3df717915561d4ac0f..582ee5fc56cb139370c76c4440b2152200bc5395 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 cbe103dce4771e855aa884f7cc5698fb8e86bade..48183f9c415888b6ed384d3141af8746f47862d9 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 eade6c6db8ef2304fbb64be2084f6f9f8a2aa453..2df6f40f677fb553445eeddbb26d369f83e9db39 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 cb09a22c6cf1d20063f47bcc705bf865719c31f6..b81218840ab3a2e6a4cdd87b5fd1bc33d803d64b 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 50ceb86c511451b5b554bef848690816219bf0c7..acf322cb9c3d29c94fa917c6403f10eed64c9e67 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 3c6da6c7bae2f0c0dc84ccd9279e03eafb279d49..9bf279e5af21e408b531ef93f018016ffb165872 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 23f6f30c52da8ac61482352d496984e5b71ebd90..afda155ef13443a911e83070ddc7771b5b523d88 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 e1c2c2caabb233dc58dd3c468cc30563309c7312..b744fe25dea93718a26a4b91bf86803571a2f871 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 76ca987b3455ec7935894a195e43b7ed83d6a7c2..5b87ed681ce73f7daa6239aab78111b81cd54489 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 0eb98acca9bc8db790c65e1225b123e30920945a..3054d0b59332e344fbe7bcc5b88e2165af7b91c1 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 a49e134f5ea6486a4b1a04bd3aa3b881ea4f13c5..20d129d067fc784ff5d1d3fefade4889480fee90 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 45956f571f83f931d793f8124c00d5be54be95b9..7ec67773585223f5aa62c18b8c637a36d3273e5a 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 5e9238a9706e17f377d10cea6f6ec5f5fd237dcb..ab264a6d21cf63a9dfafe8ef9796cbadd405ec02 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 fe3b9ebc5f556a865df8b46847e2ad05ffa17445..5f0dbefe0c26186d0b03ddcbf9766fc285f9787b 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 eb16371ee74ca134955893a5dca630310d63a508..dd4d56be85117db412222c952b334f663f51bf99 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 9dd1a66fe1d0caa56ef193041d42ae3bdb3f9f6e..07982ccaeda07f236f3f03a8981633a9847717c2 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 9ff056fbc95d0e85d1023f520d684d75d3f9b14f..51ca16b5771bbb11824ebcbcac41fb5547c8303e 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 9bb6d54ca2d1fcc87cc2cd9fb159bb4452bc07fd..8d76890b3038d87a0bb702100e8f866cd26179cd 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 4012ad5a3b16e5cbc1cc6a4433222ab69831cf97..c388293dd087d8e989db7e859b33f0c7b78d423b 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 1aa2d8bee0db17c1f245527d39a993b987222091..821408282bd0d64569e83ede29a47c9d702d18f7 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 72dcf9ff46e73dc36fc34ebc78d16cd6e8dd5e3b..f78a7311d44342ab29e08c54a66a59aca0d33ec6 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 2d7c0b4aa713dfefb4cac8bd753f060c919c8ff3..1cf50971d3f35eae2e08920cc4776aeab896ea53 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 b41fd99239243a270775e10a16549cfe2b850ba7..39619bf2ba3ab279233aad0ccb6306acc550d1d5 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 69e4f960c8159a3e75e7066fb6108e6c96aa44db..1808aa00fe57896298df02a450e9115252c599b8 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 83014a80188cce5bc97a0b97cf55b29ac2622e5d..7090f7b89948dc7b6f163b6bf4684f1b563900b1 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