[iOS] Caret is obscured by finger when dragging over an editable element
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2018 20:27:59 +0000 (20:27 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 10 Dec 2018 20:27:59 +0000 (20:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=192499
<rdar://problem/46570101>

Reviewed by Tim Horton.

Source/WebCore:

* page/DragActions.h:

Move DragHandlingMethod to DragActions.h, and drive-by fix some minor issues (i.e. make a couple of enum classes
use 8 bits, fix the indentation levels, and update the copyright year). Also add `EnumTraits` for
DragHandlingMethod so that it may be encoded over IPC.

* page/DragController.cpp:
(WebCore::dragIsHandledByDocument):

Simplify this helper function.

(WebCore::DragController::tryDocumentDrag):
* page/DragController.h:

Expose the current DragHandlingMethod via a const getter method.

(WebCore::DragController::dragHandlingMethod const):

Source/WebKit:

Add support for setting the `precise` property of `UIDropProposal` to YES when dragging over an editable area.
When enabled, this property shifts the drop location up by a small amount, allowing the user to see the drop
caret (currently, this is not the case, and it's difficult to drop text at a precise location on iOS). Changes
are covered by adding to existing API tests.

* Scripts/webkit/messages.py:
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:

Add a new version of `-_webView:willUpdateDataInteractionOperationToOperation:forSession:` that receives and
returns a UIDropProposal, so that Mail can more easily port over existing logic in its legacy-WebKit-based
compose implementation. iOS Safari is currently the only client of this private delegate, so the old version can
be easily removed once Safari adopts this new version.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didPerformDragControllerAction):

Add plumbing to send the latest drag handling method from WebPage to WebPageProxy.

(WebKit::WebPageProxy::resetCurrentDragInformation):
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::currentDragHandlingMethod const):
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView dropInteraction:sessionDidUpdate:]):

Call the new UI delegate hook when determining the drop proposal to return to UIKit. Additionally set the
`precise` bit on the drop proposal in the case where the drop handling method is either "editing rich text" or
"editing plain text".

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::performDragControllerAction):
* WebProcess/WebPage/WebPage.h:

Tools:

Augment some existing API tests to check that the `precise` flag is either on or off on `UIDropProposal`.

* TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
* TestWebKitAPI/cocoa/DragAndDropSimulator.h:
* TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
(-[DragAndDropSimulator _resetSimulatedState]):
(-[DragAndDropSimulator lastKnownDropProposal]):

Rename `currentDropProposal` to `lastKnownDropProposal`, and expose it as a readonly property.

(-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):
(-[DragAndDropSimulator _advanceProgress]):
(-[DragAndDropSimulator setShowCustomActionSheetBlock:]):
(-[DragAndDropSimulator showCustomActionSheetBlock]):
(-[DragAndDropSimulator setConvertItemProvidersBlock:]):
(-[DragAndDropSimulator convertItemProvidersBlock]):
(-[DragAndDropSimulator setOverridePerformDropBlock:]):
(-[DragAndDropSimulator overridePerformDropBlock]):
(-[DragAndDropSimulator setOverrideDragUpdateBlock:]):
(-[DragAndDropSimulator overrideDragUpdateBlock]):
(-[DragAndDropSimulator setDropCompletionBlock:]):
(-[DragAndDropSimulator dropCompletionBlock]):

Refactor these properties to return and take normal Objective-C blocks, rather than `BlockPtr`s. However, use
`BlockPtr` instance variables to manage the lifetimes of these blocks.

(-[DragAndDropSimulator _webView:willUpdateDropProposalToProposal:forSession:]):
(-[DragAndDropSimulator _webView:willUpdateDataInteractionOperationToOperation:forSession:]): Deleted.

Update this to use the new WebKit delegate hook for overriding the drop proposal.

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

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/DragActions.h
Source/WebCore/page/DragController.cpp
Source/WebCore/page/DragController.h
Source/WebKit/ChangeLog
Source/WebKit/Scripts/webkit/messages.py
Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm
Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h
Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm

index ab38a81..b8b9443 100644 (file)
@@ -1,3 +1,29 @@
+2018-12-10  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Caret is obscured by finger when dragging over an editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192499
+        <rdar://problem/46570101>
+
+        Reviewed by Tim Horton.
+
+        * page/DragActions.h:
+
+        Move DragHandlingMethod to DragActions.h, and drive-by fix some minor issues (i.e. make a couple of enum classes
+        use 8 bits, fix the indentation levels, and update the copyright year). Also add `EnumTraits` for
+        DragHandlingMethod so that it may be encoded over IPC.
+
+        * page/DragController.cpp:
+        (WebCore::dragIsHandledByDocument):
+
+        Simplify this helper function.
+
+        (WebCore::DragController::tryDocumentDrag):
+        * page/DragController.h:
+
+        Expose the current DragHandlingMethod via a const getter method.
+
+        (WebCore::DragController::dragHandlingMethod const):
+
 2018-12-10  Youenn Fablet  <youenn@apple.com>
 
         Make mock capture happen in the process used for real capture
index c3d4a41..b6776bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2012 Apple Inc.  All rights reserved.
+ * Copyright (C) 2007-2018 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #pragma once
 
 #include <limits.h>
+#include <wtf/Forward.h>
 
 namespace WebCore {
 
-    // WebCoreDragDestinationAction should be kept in sync with WebDragDestinationAction
-    typedef enum {
-        DragDestinationActionNone    = 0,
-        DragDestinationActionDHTML   = 1,
-        DragDestinationActionEdit    = 2,
-        DragDestinationActionLoad    = 4,
-        DragDestinationActionAny     = UINT_MAX
-    } DragDestinationAction;
-    
-    // WebCoreDragSourceAction should be kept in sync with WebDragSourceAction
-    typedef enum {
-        DragSourceActionNone         = 0,
-        DragSourceActionDHTML        = 1,
-        DragSourceActionImage        = 2,
-        DragSourceActionLink         = 4,
-        DragSourceActionSelection    = 8,
+// WebCoreDragDestinationAction should be kept in sync with WebDragDestinationAction.
+typedef enum {
+    DragDestinationActionNone    = 0,
+    DragDestinationActionDHTML   = 1,
+    DragDestinationActionEdit    = 2,
+    DragDestinationActionLoad    = 4,
+    DragDestinationActionAny     = UINT_MAX
+} DragDestinationAction;
+
+// WebCoreDragSourceAction should be kept in sync with WebDragSourceAction.
+typedef enum {
+    DragSourceActionNone         = 0,
+    DragSourceActionDHTML        = 1,
+    DragSourceActionImage        = 2,
+    DragSourceActionLink         = 4,
+    DragSourceActionSelection    = 8,
 #if ENABLE(ATTACHMENT_ELEMENT)
-        DragSourceActionAttachment   = 16,
+    DragSourceActionAttachment   = 16,
 #endif
 #if ENABLE(INPUT_TYPE_COLOR)
-        DragSourceActionColor        = 32,
+    DragSourceActionColor        = 32,
 #endif
-        DragSourceActionAny          = UINT_MAX
-    } DragSourceAction;
-    
-    //matches NSDragOperation
-    typedef enum {
-        DragOperationNone    = 0,
-        DragOperationCopy    = 1,
-        DragOperationLink    = 2,
-        DragOperationGeneric = 4,
-        DragOperationPrivate = 8,
-        DragOperationMove    = 16,
-        DragOperationDelete  = 32,
-        DragOperationEvery   = UINT_MAX
-    } DragOperation;
+    DragSourceActionAny          = UINT_MAX
+} DragSourceAction;
+
+// Matches NSDragOperation.
+typedef enum {
+    DragOperationNone    = 0,
+    DragOperationCopy    = 1,
+    DragOperationLink    = 2,
+    DragOperationGeneric = 4,
+    DragOperationPrivate = 8,
+    DragOperationMove    = 16,
+    DragOperationDelete  = 32,
+    DragOperationEvery   = UINT_MAX
+} DragOperation;
+
+enum class MayExtendDragSession : bool { No, Yes };
+enum class HasNonDefaultPasteboardData : bool { No, Yes };
+enum class DragHandlingMethod : uint8_t { None, EditPlainText, EditRichText, UploadFile, PageLoad, SetColor, NonDefault };
 
-    enum class MayExtendDragSession { No, Yes };
-    enum class HasNonDefaultPasteboardData { No, Yes };
-    
 } // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::DragHandlingMethod> {
+    using values = EnumValues<
+        WebCore::DragHandlingMethod,
+        WebCore::DragHandlingMethod::None,
+        WebCore::DragHandlingMethod::EditPlainText,
+        WebCore::DragHandlingMethod::EditRichText,
+        WebCore::DragHandlingMethod::UploadFile,
+        WebCore::DragHandlingMethod::PageLoad,
+        WebCore::DragHandlingMethod::SetColor,
+        WebCore::DragHandlingMethod::NonDefault
+    >;
+};
+
+} // namespace WTF
index 9ee3d46..4bb3044 100644 (file)
@@ -237,15 +237,9 @@ DragOperation DragController::dragUpdated(const DragData& dragData)
     return dragEnteredOrUpdated(dragData);
 }
 
-inline static bool dragIsHandledByDocument(DragController::DragHandlingMethod dragHandlingMethod)
+inline static bool dragIsHandledByDocument(DragHandlingMethod dragHandlingMethod)
 {
-    if (dragHandlingMethod == DragController::DragHandlingMethod::None)
-        return false;
-
-    if (dragHandlingMethod == DragController::DragHandlingMethod::PageLoad)
-        return false;
-
-    return true;
+    return dragHandlingMethod != DragHandlingMethod::None && dragHandlingMethod != DragHandlingMethod::PageLoad;
 }
 
 bool DragController::performDragOperation(const DragData& dragData)
@@ -385,7 +379,7 @@ void DragController::updateSupportedTypeIdentifiersForDragHandlingMethod(DragHan
 
 #endif
 
-DragController::DragHandlingMethod DragController::tryDocumentDrag(const DragData& dragData, DragDestinationAction actionMask, DragOperation& dragOperation)
+DragHandlingMethod DragController::tryDocumentDrag(const DragData& dragData, DragDestinationAction actionMask, DragOperation& dragOperation)
 {
     if (!m_documentUnderMouse)
         return DragHandlingMethod::None;
index 8435283..2f05f7b 100644 (file)
@@ -78,8 +78,8 @@ struct PromisedAttachmentInfo;
         void setDragOffset(const IntPoint& offset) { m_dragOffset = offset; }
         const IntPoint& dragOffset() const { return m_dragOffset; }
         DragSourceAction dragSourceAction() const { return m_dragSourceAction; }
+        DragHandlingMethod dragHandlingMethod() const { return m_dragHandlingMethod; }
 
-        enum class DragHandlingMethod { None, EditPlainText, EditRichText, UploadFile, PageLoad, SetColor, NonDefault };
         Document* documentUnderMouse() const { return m_documentUnderMouse.get(); }
         DragDestinationAction dragDestinationAction() const { return m_dragDestinationAction; }
         DragSourceAction delegateDragSourceAction(const IntPoint& rootViewPoint);
@@ -143,7 +143,7 @@ struct PromisedAttachmentInfo;
         RefPtr<Document> m_dragInitiator; // The Document (if any) that initiated the drag.
         RefPtr<HTMLInputElement> m_fileInputElementUnderMouse;
         unsigned m_numberOfItemsToBeAccepted;
-        DragHandlingMethod m_dragHandlingMethod;
+        DragHandlingMethod m_dragHandlingMethod { DragHandlingMethod::None };
 
         DragDestinationAction m_dragDestinationAction;
         DragSourceAction m_dragSourceAction;
index 77fa9b3..e4370cf 100644 (file)
@@ -1,3 +1,44 @@
+2018-12-10  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Caret is obscured by finger when dragging over an editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192499
+        <rdar://problem/46570101>
+
+        Reviewed by Tim Horton.
+
+        Add support for setting the `precise` property of `UIDropProposal` to YES when dragging over an editable area.
+        When enabled, this property shifts the drop location up by a small amount, allowing the user to see the drop
+        caret (currently, this is not the case, and it's difficult to drop text at a precise location on iOS). Changes
+        are covered by adding to existing API tests.
+
+        * Scripts/webkit/messages.py:
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+
+        Add a new version of `-_webView:willUpdateDataInteractionOperationToOperation:forSession:` that receives and
+        returns a UIDropProposal, so that Mail can more easily port over existing logic in its legacy-WebKit-based
+        compose implementation. iOS Safari is currently the only client of this private delegate, so the old version can
+        be easily removed once Safari adopts this new version.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didPerformDragControllerAction):
+
+        Add plumbing to send the latest drag handling method from WebPage to WebPageProxy.
+
+        (WebKit::WebPageProxy::resetCurrentDragInformation):
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::currentDragHandlingMethod const):
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView dropInteraction:sessionDidUpdate:]):
+
+        Call the new UI delegate hook when determining the drop proposal to return to UIKit. Additionally set the
+        `precise` bit on the drop proposal in the case where the drop handling method is either "editing rich text" or
+        "editing plain text".
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::performDragControllerAction):
+        * WebProcess/WebPage/WebPage.h:
+
 2018-12-10  Youenn Fablet  <youenn@apple.com>
 
         Make mock capture happen in the process used for real capture
index 2b6fa52..b52137b 100644 (file)
@@ -397,6 +397,7 @@ def headers_for_type(type):
         'String': ['<wtf/text/WTFString.h>'],
         'PAL::SessionID': ['<pal/SessionID.h>'],
         'WebCore::AutoplayEventFlags': ['<WebCore/AutoplayEvent.h>'],
+        'WebCore::DragHandlingMethod': ['<WebCore/DragActions.h>'],
         'WebCore::ExceptionDetails': ['<WebCore/JSDOMExceptionHandling.h>'],
         'WebCore::FileChooserSettings': ['<WebCore/FileChooser.h>'],
         'WebCore::ShareDataWithParsedURL': ['<WebCore/ShareData.h>'],
index 997468c..fe40bbe 100644 (file)
@@ -157,6 +157,7 @@ struct UIEdgeInsets;
 - (void)_webView:(WKWebView *)webView dataInteraction:(id)interaction session:(id)session didEndWithOperation:(NSUInteger)operation WK_API_AVAILABLE(ios(11.0));
 - (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray *)itemProviders WK_API_AVAILABLE(ios(11.0));
 - (NSUInteger)_webView:(WKWebView *)webView willUpdateDataInteractionOperationToOperation:(NSUInteger)operation forSession:(id)session WK_API_AVAILABLE(ios(11.0));
+- (UIDropProposal *)_webView:(WKWebView *)webView willUpdateDropProposalToProposal:(UIDropProposal *)proposal forSession:(id <UIDropSession>)session WK_API_AVAILABLE(ios(WK_IOS_TBA));
 #if TARGET_OS_IOS
 - (UITargetedDragPreview *)_webView:(WKWebView *)webView previewForLiftingItem:(UIDragItem *)item session:(id <UIDragSession>)session WK_API_AVAILABLE(ios(11.0));
 - (UITargetedDragPreview *)_webView:(WKWebView *)webView previewForCancellingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview WK_API_AVAILABLE(ios(11.0));
index 76a9653..2218a73 100644 (file)
@@ -2046,11 +2046,12 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag
 #endif
 }
 
-void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect)
+void WebPageProxy::didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect)
 {
     MESSAGE_CHECK(dragOperation <= DragOperationDelete);
 
     m_currentDragOperation = static_cast<DragOperation>(dragOperation);
+    m_currentDragHandlingMethod = dragHandlingMethod;
     m_currentDragIsOverFileInput = mouseIsOverFileInput;
     m_currentDragNumberOfFilesToBeAccepted = numberOfItemsToBeAccepted;
     setDragCaretRect(insertionRect);
@@ -2099,6 +2100,7 @@ void WebPageProxy::didEndDragging()
 void WebPageProxy::resetCurrentDragInformation()
 {
     m_currentDragOperation = WebCore::DragOperationNone;
+    m_currentDragHandlingMethod = DragHandlingMethod::None;
     m_currentDragIsOverFileInput = false;
     m_currentDragNumberOfFilesToBeAccepted = 0;
     setDragCaretRect({ });
index 53d8c3d..b7e3ada 100644 (file)
@@ -973,7 +973,7 @@ public:
     void performDragOperation(WebCore::DragData&, const String& dragStorageName, SandboxExtension::Handle&&, SandboxExtension::HandleArray&&);
     void didPerformDragOperation(bool handled);
 
-    void didPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const WebCore::IntRect& insertionRect);
+    void didPerformDragControllerAction(uint64_t dragOperation, WebCore::DragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const WebCore::IntRect& insertionRect);
     void dragEnded(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t operation);
     void didStartDrag();
     void dragCancelled();
@@ -1029,6 +1029,7 @@ public:
 
 #if ENABLE(DRAG_SUPPORT)
     WebCore::DragOperation currentDragOperation() const { return m_currentDragOperation; }
+    WebCore::DragHandlingMethod currentDragHandlingMethod() const { return m_currentDragHandlingMethod; }
     bool currentDragIsOverFileInput() const { return m_currentDragIsOverFileInput; }
     unsigned currentDragNumberOfFilesToBeAccepted() const { return m_currentDragNumberOfFilesToBeAccepted; }
     WebCore::IntRect currentDragCaretRect() const { return m_currentDragCaretRect; }
@@ -2151,6 +2152,7 @@ private:
     // Current drag destination details are delivered as an asynchronous response,
     // so we preserve them to be used when the next dragging delegate call is made.
     WebCore::DragOperation m_currentDragOperation { WebCore::DragOperationNone };
+    WebCore::DragHandlingMethod m_currentDragHandlingMethod { WebCore::DragHandlingMethod::None };
     bool m_currentDragIsOverFileInput { false };
     unsigned m_currentDragNumberOfFilesToBeAccepted { 0 };
     WebCore::IntRect m_currentDragCaretRect;
index 5e7056b..17a69e1 100644 (file)
@@ -311,7 +311,7 @@ messages -> WebPageProxy {
 
     # Drag and drop messages
 #if ENABLE(DRAG_SUPPORT)
-    DidPerformDragControllerAction(uint64_t dragOperation, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect)
+    DidPerformDragControllerAction(uint64_t dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect)
     DidEndDragging();
 #endif
 #if PLATFORM(COCOA) && ENABLE(DRAG_SUPPORT)
index 04dc797..b806fa4 100644 (file)
@@ -5887,11 +5887,18 @@ static NSArray<NSItemProvider *> *extractItemProvidersFromDropSession(id <UIDrop
     _page->dragUpdated(dragData, "data interaction pasteboard");
     _dragDropInteractionState.dropSessionDidEnterOrUpdate(session, dragData);
 
-    NSUInteger operation = dropOperationForWebCoreDragOperation(_page->currentDragOperation());
-    if ([self.webViewUIDelegate respondsToSelector:@selector(_webView:willUpdateDataInteractionOperationToOperation:forSession:)])
-        operation = [self.webViewUIDelegate _webView:_webView willUpdateDataInteractionOperationToOperation:operation forSession:session];
-
-    return [[[UIDropProposal alloc] initWithDropOperation:static_cast<UIDropOperation>(operation)] autorelease];
+    auto delegate = self.webViewUIDelegate;
+    auto operation = dropOperationForWebCoreDragOperation(_page->currentDragOperation());
+    if ([delegate respondsToSelector:@selector(_webView:willUpdateDataInteractionOperationToOperation:forSession:)])
+        operation = static_cast<UIDropOperation>([delegate _webView:_webView willUpdateDataInteractionOperationToOperation:operation forSession:session]);
+
+    auto proposal = adoptNS([[UIDropProposal alloc] initWithDropOperation:static_cast<UIDropOperation>(operation)]);
+    auto dragHandlingMethod = _page->currentDragHandlingMethod();
+    [proposal setPrecise:dragHandlingMethod == DragHandlingMethod::EditPlainText || dragHandlingMethod == DragHandlingMethod::EditRichText];
+    if ([delegate respondsToSelector:@selector(_webView:willUpdateDropProposalToProposal:forSession:)])
+        proposal = [delegate _webView:_webView willUpdateDropProposalToProposal:proposal.get() forSession:session];
+
+    return proposal.autorelease();
 }
 
 - (void)dropInteraction:(UIDropInteraction *)interaction sessionDidExit:(id <UIDropSession>)session
index c5542b2..99a069c 100644 (file)
@@ -3620,7 +3620,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana
 void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t draggingSourceOperationMask, WebSelectionData&& selection, uint32_t flags)
 {
     if (!m_page) {
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0, { }));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }));
         return;
     }
 
@@ -3628,12 +3628,12 @@ void WebPage::performDragControllerAction(DragControllerAction action, const Int
     switch (action) {
     case DragControllerAction::Entered: {
         DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }));
         return;
     }
     case DragControllerAction::Updated: {
         DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), { }));
         return;
     }
     case DragControllerAction::Exited:
@@ -3651,24 +3651,24 @@ void WebPage::performDragControllerAction(DragControllerAction action, const Int
 void WebPage::performDragControllerAction(DragControllerAction action, const WebCore::DragData& dragData, SandboxExtension::Handle&& sandboxExtensionHandle, SandboxExtension::HandleArray&& sandboxExtensionsHandleArray)
 {
     if (!m_page) {
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0, { }));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }));
         return;
     }
 
     switch (action) {
     case DragControllerAction::Entered: {
         DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
         return;
     }
     case DragControllerAction::Updated: {
         DragOperation resolvedDragOperation = m_page->dragController().dragUpdated(dragData);
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().dragHandlingMethod(), m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted(), m_page->dragCaretController().caretRectInRootViewCoordinates()));
         return;
     }
     case DragControllerAction::Exited:
         m_page->dragController().dragExited(dragData);
-        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0, { }));
+        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, DragHandlingMethod::None, false, 0, { }));
         return;
         
     case DragControllerAction::PerformDragOperation: {
index 83892e5..d4a9b7d 100644 (file)
@@ -167,6 +167,7 @@ class TextCheckingRequest;
 class VisiblePosition;
 
 enum SyntheticClickType : int8_t;
+enum class DragHandlingMethod : uint8_t;
 enum class ShouldTreatAsContinuingLoad : bool;
 enum class TextIndicatorPresentationTransition : uint8_t;
 enum class WritingDirection : uint8_t;
index 5f8a578..7592afc 100644 (file)
@@ -1,3 +1,42 @@
+2018-12-10  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Caret is obscured by finger when dragging over an editable element
+        https://bugs.webkit.org/show_bug.cgi?id=192499
+        <rdar://problem/46570101>
+
+        Reviewed by Tim Horton.
+
+        Augment some existing API tests to check that the `precise` flag is either on or off on `UIDropProposal`.
+
+        * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
+        * TestWebKitAPI/cocoa/DragAndDropSimulator.h:
+        * TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
+        (-[DragAndDropSimulator _resetSimulatedState]):
+        (-[DragAndDropSimulator lastKnownDropProposal]):
+
+        Rename `currentDropProposal` to `lastKnownDropProposal`, and expose it as a readonly property.
+
+        (-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):
+        (-[DragAndDropSimulator _advanceProgress]):
+        (-[DragAndDropSimulator setShowCustomActionSheetBlock:]):
+        (-[DragAndDropSimulator showCustomActionSheetBlock]):
+        (-[DragAndDropSimulator setConvertItemProvidersBlock:]):
+        (-[DragAndDropSimulator convertItemProvidersBlock]):
+        (-[DragAndDropSimulator setOverridePerformDropBlock:]):
+        (-[DragAndDropSimulator overridePerformDropBlock]):
+        (-[DragAndDropSimulator setOverrideDragUpdateBlock:]):
+        (-[DragAndDropSimulator overrideDragUpdateBlock]):
+        (-[DragAndDropSimulator setDropCompletionBlock:]):
+        (-[DragAndDropSimulator dropCompletionBlock]):
+
+        Refactor these properties to return and take normal Objective-C blocks, rather than `BlockPtr`s. However, use
+        `BlockPtr` instance variables to manage the lifetimes of these blocks.
+
+        (-[DragAndDropSimulator _webView:willUpdateDropProposalToProposal:forSession:]):
+        (-[DragAndDropSimulator _webView:willUpdateDataInteractionOperationToOperation:forSession:]): Deleted.
+
+        Update this to use the new WebKit delegate hook for overriding the drop proposal.
+
 2018-12-10  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         [WPE][GTK] run-minibrowser improperly creates webkit-flatpak environment
index 2c81e57..a75abe8 100644 (file)
@@ -272,6 +272,7 @@ TEST(DragAndDropTests, ImageToContentEditable)
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 215, 174) ], [simulator finalSelectionRects]);
     checkFirstTypeIsPresentAndSecondTypeIsMissing(simulator.get(), kUTTypePNG, kUTTypeFileURL);
     checkEstimatedSize(simulator.get(), { 215, 174 });
+    EXPECT_TRUE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, CanStartDragOnEnormousImage)
@@ -316,6 +317,7 @@ TEST(DragAndDropTests, ImageInLinkToInput)
     checkSelectionRectsWithLogging(@[ makeCGRectValue(101, 241, 2057, 232) ], [simulator finalSelectionRects]);
     checkSuggestedNameAndEstimatedSize(simulator.get(), @"icon.png", { 215, 174 });
     checkTypeIdentifierIsRegisteredAtIndex(simulator.get(), (__bridge NSString *)kUTTypePNG, 0);
+    EXPECT_TRUE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ImageInLinkWithoutHREFToInput)
@@ -363,6 +365,7 @@ TEST(DragAndDropTests, ContentEditableToContentEditable)
     EXPECT_TRUE([observedEventNames containsObject:@"drop"]);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(1, 201, 961, 227) ], [simulator finalSelectionRects]);
     checkRichTextTypePrecedesPlainTextType(simulator.get());
+    EXPECT_TRUE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ContentEditableToTextarea)
@@ -383,6 +386,7 @@ TEST(DragAndDropTests, ContentEditableToTextarea)
     EXPECT_TRUE([observedEventNames containsObject:@"drop"]);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(6, 203, 990, 232) ], [simulator finalSelectionRects]);
     checkRichTextTypePrecedesPlainTextType(simulator.get());
+    EXPECT_TRUE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, NonEditableTextSelectionToTextarea)
@@ -413,6 +417,7 @@ TEST(DragAndDropTests, ContentEditableMoveParagraphs)
     EXPECT_FALSE(secondParagraphOffset == NSNotFound);
     EXPECT_GT(firstParagraphOffset, secondParagraphOffset);
     checkSelectionRectsWithLogging(@[ makeCGRectValue(190, 100, 130, 20), makeCGRectValue(0, 120, 320, 100), makeCGRectValue(0, 220, 252, 20) ], [simulator finalSelectionRects]);
+    EXPECT_TRUE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, DragImageFromContentEditable)
@@ -629,6 +634,7 @@ TEST(DragAndDropTests, ExternalSourceInlineTextToFileInput)
     [simulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
 
     EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"output.value"]);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceJSONToFileInput)
@@ -645,6 +651,7 @@ TEST(DragAndDropTests, ExternalSourceJSONToFileInput)
     [simulator runFrom:CGPointMake(200, 100) to:CGPointMake(100, 100)];
 
     EXPECT_WK_STREQ("application/json", [webView stringByEvaluatingJavaScript:@"output.value"]);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceImageToFileInput)
@@ -662,6 +669,7 @@ TEST(DragAndDropTests, ExternalSourceImageToFileInput)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("image/jpeg", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceHTMLToUploadArea)
@@ -681,6 +689,7 @@ TEST(DragAndDropTests, ExternalSourceHTMLToUploadArea)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceMoveOperationNotAllowed)
@@ -718,6 +727,7 @@ TEST(DragAndDropTests, ExternalSourceZIPArchiveAndURLToSingleFileInput)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceZIPArchiveToUploadArea)
@@ -734,6 +744,7 @@ TEST(DragAndDropTests, ExternalSourceZIPArchiveToUploadArea)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("application/zip", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceImageAndHTMLToSingleFileInput)
@@ -755,6 +766,7 @@ TEST(DragAndDropTests, ExternalSourceImageAndHTMLToSingleFileInput)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceImageAndHTMLToMultipleFileInput)
@@ -777,6 +789,7 @@ TEST(DragAndDropTests, ExternalSourceImageAndHTMLToMultipleFileInput)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("image/jpeg, text/html", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceImageAndHTMLToUploadArea)
@@ -803,6 +816,7 @@ TEST(DragAndDropTests, ExternalSourceImageAndHTMLToUploadArea)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("image/jpeg, text/html, text/html", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 TEST(DragAndDropTests, ExternalSourceHTMLToContentEditable)
@@ -1029,6 +1043,7 @@ TEST(DragAndDropTests, ExternalSourceOverrideDropFileUpload)
 
     NSString *outputValue = [webView stringByEvaluatingJavaScript:@"output.value"];
     EXPECT_WK_STREQ("text/html", outputValue.UTF8String);
+    EXPECT_FALSE([simulator lastKnownDropProposal].precise);
 }
 
 #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 110300
@@ -1154,9 +1169,8 @@ TEST(DragAndDropTests, OverrideDrop)
     __block bool finishedLoadingData = false;
     auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
     [simulator setExternalItemProviders:@[ simulatedItemProvider.get() ]];
-    [simulator setOverrideDragUpdateBlock:^NSUInteger(NSUInteger operation, id session)
-    {
-        EXPECT_EQ(0U, operation);
+    [simulator setOverrideDragUpdateBlock:[] (UIDropOperation operation, id <UIDropSession> session) {
+        EXPECT_EQ(UIDropOperationCancel, operation);
         return UIDropOperationCopy;
     }];
     [simulator setDropCompletionBlock:^(BOOL handled, NSArray *itemProviders) {
index 4fe0b84..4be9732 100644 (file)
@@ -95,12 +95,14 @@ typedef NSDictionary<NSNumber *, NSValue *> *ProgressToCGPointValueMap;
 @property (nonatomic) BOOL allowsFocusToStartInputSession;
 @property (nonatomic) BOOL shouldEnsureUIApplication;
 @property (nonatomic) BOOL shouldAllowMoveOperation;
-@property (nonatomic) BlockPtr<BOOL(_WKActivatedElementInfo *)> showCustomActionSheetBlock;
-@property (nonatomic) BlockPtr<NSArray *(NSItemProvider *, NSArray *, NSDictionary *)> convertItemProvidersBlock;
-@property (nonatomic) BlockPtr<NSArray *(id <UIDropSession>)> overridePerformDropBlock;
 @property (nonatomic, strong) NSArray *externalItemProviders;
-@property (nonatomic) BlockPtr<NSUInteger(NSUInteger, id)> overrideDragUpdateBlock;
-@property (nonatomic) BlockPtr<void(BOOL, NSArray *)> dropCompletionBlock;
+@property (nonatomic, readonly) UIDropProposal *lastKnownDropProposal;
+
+@property (nonatomic, copy) BOOL(^showCustomActionSheetBlock)(_WKActivatedElementInfo *);
+@property (nonatomic, copy) NSArray *(^convertItemProvidersBlock)(NSItemProvider *, NSArray *, NSDictionary *);
+@property (nonatomic, copy) NSArray *(^overridePerformDropBlock)(id <UIDropSession>);
+@property (nonatomic, copy) void(^dropCompletionBlock)(BOOL, NSArray *);
+@property (nonatomic, copy) UIDropOperation(^overrideDragUpdateBlock)(UIDropOperation, id <UIDropSession>);
 
 @property (nonatomic, readonly) NSArray *sourceItemProviders;
 @property (nonatomic, readonly) NSArray *observedEventNames;
index 3d23efc..4cb8518 100644 (file)
@@ -316,7 +316,13 @@ static NSArray *dragAndDropEventNames()
     DragAndDropPhase _phase;
 
     BOOL _suppressedSelectionCommandsDuringDrop;
-    RetainPtr<UIDropProposal> _currentDropProposal;
+    RetainPtr<UIDropProposal> _lastKnownDropProposal;
+
+    BlockPtr<BOOL(_WKActivatedElementInfo *)> _showCustomActionSheetBlock;
+    BlockPtr<NSArray *(NSItemProvider *, NSArray *, NSDictionary *)> _convertItemProvidersBlock;
+    BlockPtr<NSArray *(id <UIDropSession>)> _overridePerformDropBlock;
+    BlockPtr<UIDropOperation(UIDropOperation, id)> _overrideDragUpdateBlock;
+    BlockPtr<void(BOOL, NSArray *)> _dropCompletionBlock;
 }
 
 - (instancetype)initWithWebViewFrame:(CGRect)frame
@@ -367,7 +373,7 @@ static NSArray *dragAndDropEventNames()
     _finalSelectionRects = @[ ];
     _dragSession = nil;
     _dropSession = nil;
-    _currentDropProposal = nil;
+    _lastKnownDropProposal = nil;
     _lastKnownDragCaretRect = CGRectZero;
     _remainingAdditionalItemRequestLocationsByProgress = nil;
     _queuedAdditionalItemRequestLocations = adoptNS([[NSMutableArray alloc] init]);
@@ -380,6 +386,11 @@ static NSArray *dragAndDropEventNames()
     return _observedEventNames.get();
 }
 
+- (UIDropProposal *)lastKnownDropProposal
+{
+    return _lastKnownDropProposal.get();
+}
+
 - (void)simulateAllTouchesCanceled:(NSNotification *)notification
 {
     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_advanceProgress) object:nil];
@@ -448,7 +459,7 @@ static NSArray *dragAndDropEventNames()
 - (void)_concludeDropAndPerformOperationIfNecessary
 {
     _lastKnownDragCaretRect = [_webView _dragCaretRect];
-    auto operation = [_currentDropProposal operation];
+    auto operation = [_lastKnownDropProposal operation];
     if (operation != UIDropOperationCancel && operation != UIDropOperationForbidden) {
         [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] performDrop:_dropSession.get()];
         _phase = DragAndDropPhasePerformingDrop;
@@ -569,9 +580,9 @@ static NSArray *dragAndDropEventNames()
         _phase = DragAndDropPhaseEntered;
         break;
     case DragAndDropPhaseEntered: {
-        _currentDropProposal = [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidUpdate:_dropSession.get()];
-        if (![self shouldAllowMoveOperation] && [_currentDropProposal operation] == UIDropOperationMove)
-            _currentDropProposal = adoptNS([[UIDropProposal alloc] initWithDropOperation:UIDropOperationCancel]);
+        _lastKnownDropProposal = [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] sessionDidUpdate:_dropSession.get()];
+        if (![self shouldAllowMoveOperation] && [_lastKnownDropProposal operation] == UIDropOperationMove)
+            _lastKnownDropProposal = adoptNS([[UIDropProposal alloc] initWithDropOperation:UIDropOperationCancel]);
         break;
     }
     default:
@@ -654,6 +665,56 @@ static NSArray *dragAndDropEventNames()
     return _webView.get();
 }
 
+- (void)setShowCustomActionSheetBlock:(BOOL(^)(_WKActivatedElementInfo *))showCustomActionSheetBlock
+{
+    _showCustomActionSheetBlock = showCustomActionSheetBlock;
+}
+
+- (BOOL(^)(_WKActivatedElementInfo *))showCustomActionSheetBlock
+{
+    return _showCustomActionSheetBlock.get();
+}
+
+- (void)setConvertItemProvidersBlock:(NSArray *(^)(NSItemProvider *, NSArray *, NSDictionary *))convertItemProvidersBlock
+{
+    _convertItemProvidersBlock = convertItemProvidersBlock;
+}
+
+- (NSArray *(^)(NSItemProvider *, NSArray *, NSDictionary *))convertItemProvidersBlock
+{
+    return _convertItemProvidersBlock.get();
+}
+
+- (void)setOverridePerformDropBlock:(NSArray *(^)(id <UIDropSession>))overridePerformDropBlock
+{
+    _overridePerformDropBlock = overridePerformDropBlock;
+}
+
+- (NSArray *(^)(id <UIDropSession>))overridePerformDropBlock
+{
+    return _overridePerformDropBlock.get();
+}
+
+- (void)setOverrideDragUpdateBlock:(UIDropOperation(^)(UIDropOperation, id <UIDropSession>))overrideDragUpdateBlock
+{
+    _overrideDragUpdateBlock = overrideDragUpdateBlock;
+}
+
+- (UIDropOperation(^)(UIDropOperation, id <UIDropSession>))overrideDragUpdateBlock
+{
+    return _overrideDragUpdateBlock.get();
+}
+
+- (void)setDropCompletionBlock:(void(^)(BOOL, NSArray *))dropCompletionBlock
+{
+    _dropCompletionBlock = dropCompletionBlock;
+}
+
+- (void(^)(BOOL, NSArray *))dropCompletionBlock
+{
+    return _dropCompletionBlock.get();
+}
+
 #pragma mark - WKUIDelegatePrivate
 
 - (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray<NSItemProvider *> *)itemProviders
@@ -665,9 +726,12 @@ static NSArray *dragAndDropEventNames()
         self.dropCompletionBlock(handled, itemProviders);
 }
 
-- (NSUInteger)_webView:(WKWebView *)webView willUpdateDataInteractionOperationToOperation:(NSUInteger)operation forSession:(id)session
+- (UIDropProposal *)_webView:(WKWebView *)webView willUpdateDropProposalToProposal:(UIDropProposal *)proposal forSession:(id <UIDropSession>)session
 {
-    return self.overrideDragUpdateBlock ? self.overrideDragUpdateBlock(operation, session) : operation;
+    if (!self.overrideDragUpdateBlock)
+        return proposal;
+
+    return [[[UIDropProposal alloc] initWithDropOperation:self.overrideDragUpdateBlock(proposal.operation, session)] autorelease];
 }
 
 - (NSArray *)_webView:(WKWebView *)webView adjustedDataInteractionItemProvidersForItemProvider:(NSItemProvider *)itemProvider representingObjects:(NSArray *)representingObjects additionalData:(NSDictionary *)additionalData