⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 244056 in webkit


Ignore:
Timestamp:
Apr 8, 2019, 3:49:20 PM (7 years ago)
Author:
Wenson Hsieh
Message:

[iOS] Do not allow starting selection drags when selection views are not visible
https://bugs.webkit.org/show_bug.cgi?id=196686
<rdar://problem/49399192>

Reviewed by Tim Horton.

Source/WebCore:

See WebKit ChangeLog for more details.

Tests: DragAndDropTests.CanDragImageWhenNotFirstResponder

DragAndDropTests.DoNotPerformSelectionDragWhenNotFirstResponder

  • page/DragController.cpp:

(WebCore::DragController::draggableElement const):

Make this respect the case where m_dragSourceAction does not include DragSourceActionSelection. All the other
drag source types are currently consulted in this method, with the exception of DragSourceActionSelection.

Source/WebKit:

Currently, on iOS, it's possible to start dragging selected text in a web view even if the selection itself is
not visible. This can happen if the user selects some text, focuses a native text field, and then long presses
the previously selected text. This is because the text is still selected in the document since we don't clear
the selection when resigning first responder on iOS, despite the fact that the native selection view is no
longer present.

To fix this, we add plumbing to specify the set of allowed drag source actions when requesting drag start; this
set of allowed drag source actions only includes DragSourceActionSelection if the selection view can be visible
(i.e. the content view is first responder, and isn't suppressing text interactions). We then update WebPage's
allowed drag source actions with this given set of actions, while sending "dragstart" to the page.

  • UIProcess/WebPageProxy.h:
  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView hasSelectablePositionAtPoint:]):
(-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):

Only bail out of text selection in text that is already selected if the web view allows dragging text selections
(i.e. the web view is first responder, and is not suppressing text interactions).

(-[WKContentView _allowedDragSourceActions]):
(-[WKContentView _dragInteraction:itemsForAddingToSession:withTouchAtPoint:completion:]):
(-[WKContentView _dragInteraction:prepareForSession:completion:]):

Pass the set of allowed drag source actions when requesting a drag start or adding items to an existing session.

  • UIProcess/ios/WebPageProxyIOS.mm:

(WebKit::WebPageProxy::requestDragStart):
(WebKit::WebPageProxy::requestAdditionalItemsForDragSession):

Plumb the allowed drag source actions from the UI process (WKContentView) over to the web process (WebPage).

  • WebProcess/WebCoreSupport/WebDragClient.cpp:

(WebKit::WebDragClient::dragSourceActionMaskForPoint):

Instead of always returning Any, consult WebPage's allowed drag source actions.

  • WebProcess/WebPage/WebPage.h:

(WebKit::WebPage::allowedDragSourceActions const):

  • WebProcess/WebPage/WebPage.messages.in:
  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::WebPage::requestDragStart):
(WebKit::WebPage::requestAdditionalItemsForDragSession):

Set WebPage's allowed drag source actions to the given set of actions when sending a drag start to the page.

Tools:

Adjust some existing API tests to make the web view become first responder before trying to begin dragging, and
also add some new API tests to cover scenarios where the web view is not first responder.

  • TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:

(TestWebKitAPI::TEST):

  • TestWebKitAPI/cocoa/DragAndDropSimulator.h:

Add a switch to optionally make the web view first responder when starting the simulated drag.

  • TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:

(-[DragAndDropSimulator initWithWebView:]):
(-[DragAndDropSimulator runFrom:to:additionalItemRequestLocations:]):

Location:
trunk
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r244054 r244056  
     12019-04-08  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS] Do not allow starting selection drags when selection views are not visible
     4        https://bugs.webkit.org/show_bug.cgi?id=196686
     5        <rdar://problem/49399192>
     6
     7        Reviewed by Tim Horton.
     8
     9        See WebKit ChangeLog for more details.
     10
     11        Tests:  DragAndDropTests.CanDragImageWhenNotFirstResponder
     12                DragAndDropTests.DoNotPerformSelectionDragWhenNotFirstResponder
     13
     14        * page/DragController.cpp:
     15        (WebCore::DragController::draggableElement const):
     16
     17        Make this respect the case where m_dragSourceAction does not include DragSourceActionSelection. All the other
     18        drag source types are currently consulted in this method, with the exception of DragSourceActionSelection.
     19
    1202019-04-08  Youenn Fablet  <youenn@apple.com>
    221
  • trunk/Source/WebCore/page/DragController.cpp

    r243785 r244056  
    827827
    828828    // We either have nothing to drag or we have a selection and we're not over a draggable element.
    829     return (state.type & DragSourceActionSelection) ? startElement : nullptr;
     829    if (state.type & DragSourceActionSelection && m_dragSourceAction & DragSourceActionSelection)
     830        return startElement;
     831
     832    return nullptr;
    830833}
    831834
  • trunk/Source/WebKit/ChangeLog

    r244050 r244056  
     12019-04-08  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS] Do not allow starting selection drags when selection views are not visible
     4        https://bugs.webkit.org/show_bug.cgi?id=196686
     5        <rdar://problem/49399192>
     6
     7        Reviewed by Tim Horton.
     8
     9        Currently, on iOS, it's possible to start dragging selected text in a web view even if the selection itself is
     10        not visible. This can happen if the user selects some text, focuses a native text field, and then long presses
     11        the previously selected text. This is because the text is still selected in the document since we don't clear
     12        the selection when resigning first responder on iOS, despite the fact that the native selection view is no
     13        longer present.
     14
     15        To fix this, we add plumbing to specify the set of allowed drag source actions when requesting drag start; this
     16        set of allowed drag source actions only includes DragSourceActionSelection if the selection view can be visible
     17        (i.e. the content view is first responder, and isn't suppressing text interactions). We then update WebPage's
     18        allowed drag source actions with this given set of actions, while sending "dragstart" to the page.
     19
     20        * UIProcess/WebPageProxy.h:
     21        * UIProcess/ios/WKContentViewInteraction.mm:
     22        (-[WKContentView hasSelectablePositionAtPoint:]):
     23        (-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):
     24
     25        Only bail out of text selection in text that is already selected if the web view allows dragging text selections
     26        (i.e. the web view is first responder, and is not suppressing text interactions).
     27
     28        (-[WKContentView _allowedDragSourceActions]):
     29        (-[WKContentView _dragInteraction:itemsForAddingToSession:withTouchAtPoint:completion:]):
     30        (-[WKContentView _dragInteraction:prepareForSession:completion:]):
     31
     32        Pass the set of allowed drag source actions when requesting a drag start or adding items to an existing session.
     33
     34        * UIProcess/ios/WebPageProxyIOS.mm:
     35        (WebKit::WebPageProxy::requestDragStart):
     36        (WebKit::WebPageProxy::requestAdditionalItemsForDragSession):
     37
     38        Plumb the allowed drag source actions from the UI process (WKContentView) over to the web process (WebPage).
     39
     40        * WebProcess/WebCoreSupport/WebDragClient.cpp:
     41        (WebKit::WebDragClient::dragSourceActionMaskForPoint):
     42
     43        Instead of always returning Any, consult WebPage's allowed drag source actions.
     44
     45        * WebProcess/WebPage/WebPage.h:
     46        (WebKit::WebPage::allowedDragSourceActions const):
     47        * WebProcess/WebPage/WebPage.messages.in:
     48        * WebProcess/WebPage/ios/WebPageIOS.mm:
     49        (WebKit::WebPage::requestDragStart):
     50        (WebKit::WebPage::requestAdditionalItemsForDragSession):
     51
     52        Set WebPage's allowed drag source actions to the given set of actions when sending a drag start to the page.
     53
    1542019-04-08  Justin Fan  <justin_fan@apple.com>
    255
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r243961 r244056  
    717717    void didHandleDragStartRequest(bool started);
    718718    void didHandleAdditionalDragItemsRequest(bool added);
    719     void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition);
    720     void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition);
     719    void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, WebCore::DragSourceAction allowedActions);
     720    void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, WebCore::DragSourceAction allowedActions);
    721721    void didConcludeEditDrag(Optional<WebCore::TextIndicatorData>);
    722722#endif
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r243963 r244056  
    20542054        return NO;
    20552055
    2056 #if ENABLE(DATA_INTERACTION)
    2057     if (_positionInformation.hasSelectionAtPosition) {
    2058         // If the position might initiate a data interaction, we don't want to consider the content at this position to be selectable.
     2056#if ENABLE(DRAG_SUPPORT)
     2057    if (_positionInformation.hasSelectionAtPosition && self._allowedDragSourceActions & WebCore::DragSourceActionSelection) {
     2058        // If the position might initiate a drag, we don't want to consider the content at this position to be selectable.
    20592059        // FIXME: This should be renamed to something more precise, such as textSelectionShouldRecognizeGestureAtPoint:
    20602060        return NO;
     
    20942094        return NO;
    20952095
    2096 #if ENABLE(DATA_INTERACTION)
    2097     if (_positionInformation.hasSelectionAtPosition && gesture == UIWKGestureLoupe) {
    2098         // If the position might initiate data interaction, we don't want to change the selection.
     2096#if ENABLE(DRAG_SUPPORT)
     2097    if (_positionInformation.hasSelectionAtPosition && gesture == UIWKGestureLoupe && self._allowedDragSourceActions & WebCore::DragSourceActionSelection) {
     2098        // If the position might initiate a drag, we don't want to change the selection.
    20992099        return NO;
    21002100    }
     
    62906290}
    62916291
     6292- (WebCore::DragSourceAction)_allowedDragSourceActions
     6293{
     6294    auto allowedActions = WebCore::DragSourceActionAny;
     6295    if (!self.isFirstResponder || !_suppressSelectionAssistantReasons.isEmpty()) {
     6296        // Don't allow starting a drag on a selection when selection views are not visible.
     6297        allowedActions = static_cast<WebCore::DragSourceAction>(allowedActions & ~WebCore::DragSourceActionSelection);
     6298    }
     6299    return allowedActions;
     6300}
     6301
    62926302- (id <UIDragDropSession>)currentDragOrDropSession
    62936303{
     
    64496459
    64506460    _dragDropInteractionState.dragSessionWillRequestAdditionalItem(completion);
    6451     _page->requestAdditionalItemsForDragSession(WebCore::roundedIntPoint(point), WebCore::roundedIntPoint(point));
     6461    _page->requestAdditionalItemsForDragSession(WebCore::roundedIntPoint(point), WebCore::roundedIntPoint(point), self._allowedDragSourceActions);
    64526462}
    64536463
     
    64696479
    64706480    auto dragOrigin = WebCore::roundedIntPoint([session locationInView:self]);
    6471     _page->requestDragStart(dragOrigin, WebCore::roundedIntPoint([self convertPoint:dragOrigin toView:self.window]));
     6481    _page->requestDragStart(dragOrigin, WebCore::roundedIntPoint([self convertPoint:dragOrigin toView:self.window]), self._allowedDragSourceActions);
    64726482
    64736483    RELEASE_LOG(DragAndDrop, "Drag session requested: %p at origin: {%d, %d}", session, dragOrigin.x(), dragOrigin.y());
  • trunk/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm

    r243961 r244056  
    11781178}
    11791179
    1180 void WebPageProxy::requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition)
     1180void WebPageProxy::requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, WebCore::DragSourceAction allowedActions)
    11811181{
    11821182    if (hasRunningProcess())
    1183         m_process->send(Messages::WebPage::RequestDragStart(clientPosition, globalPosition), m_pageID);
    1184 }
    1185 
    1186 void WebPageProxy::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition)
     1183        m_process->send(Messages::WebPage::RequestDragStart(clientPosition, globalPosition, allowedActions), m_pageID);
     1184}
     1185
     1186void WebPageProxy::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition, WebCore::DragSourceAction allowedActions)
    11871187{
    11881188    if (hasRunningProcess())
    1189         m_process->send(Messages::WebPage::RequestAdditionalItemsForDragSession(clientPosition, globalPosition), m_pageID);
     1189        m_process->send(Messages::WebPage::RequestAdditionalItemsForDragSession(clientPosition, globalPosition, allowedActions), m_pageID);
    11901190}
    11911191
  • trunk/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp

    r235205 r244056  
    4848DragSourceAction WebDragClient::dragSourceActionMaskForPoint(const IntPoint&)
    4949{
    50     return DragSourceActionAny;
     50    return m_page->allowedDragSourceActions();
    5151}
    5252
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r243863 r244056  
    5858#include <WebCore/DictionaryPopupInfo.h>
    5959#include <WebCore/DisabledAdaptations.h>
     60#include <WebCore/DragActions.h>
    6061#include <WebCore/FrameLoaderTypes.h>
    6162#include <WebCore/HTMLMenuElement.h>
     
    847848    void didStartDrag();
    848849    void dragCancelled();
     850    WebCore::DragSourceAction allowedDragSourceActions() const { return m_allowedDragSourceActions; }
    849851#endif
    850852
     
    12301232
    12311233#if PLATFORM(IOS_FAMILY) && ENABLE(DATA_INTERACTION)
    1232     void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition);
    1233     void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition);
     1234    void requestDragStart(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t allowedActions);
     1235    void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, uint64_t allowedActions);
    12341236#endif
    12351237
     
    17331735#if ENABLE(DRAG_SUPPORT)
    17341736    bool m_isStartingDrag { false };
     1737    WebCore::DragSourceAction m_allowedDragSourceActions { WebCore::DragSourceActionAny };
    17351738#endif
    17361739
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in

    r243354 r244056  
    302302
    303303#if ENABLE(DATA_INTERACTION)
    304     RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition)
    305     RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition)
     304    RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t allowedActions)
     305    RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t allowedActions)
    306306#endif
    307307
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r243855 r244056  
    715715
    716716#if ENABLE(DATA_INTERACTION)
    717 void WebPage::requestDragStart(const IntPoint& clientPosition, const IntPoint& globalPosition)
    718 {
     717void WebPage::requestDragStart(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t allowedActions)
     718{
     719    SetForScope<WebCore::DragSourceAction> allowedActionsForScope(m_allowedDragSourceActions, static_cast<WebCore::DragSourceAction>(allowedActions));
    719720    bool didStart = m_page->mainFrame().eventHandler().tryToBeginDragAtPoint(clientPosition, globalPosition);
    720721    send(Messages::WebPageProxy::DidHandleDragStartRequest(didStart));
    721722}
    722723
    723 void WebPage::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition)
    724 {
     724void WebPage::requestAdditionalItemsForDragSession(const IntPoint& clientPosition, const IntPoint& globalPosition, uint64_t allowedActions)
     725{
     726    SetForScope<WebCore::DragSourceAction> allowedActionsForScope(m_allowedDragSourceActions, static_cast<WebCore::DragSourceAction>(allowedActions));
    725727    // To augment the platform drag session with additional items, end the current drag session and begin a new drag session with the new drag item.
    726728    // This process is opaque to the UI process, which still maintains the old drag item in its drag session. Similarly, this persistent drag session
  • trunk/Tools/ChangeLog

    r244050 r244056  
     12019-04-08  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS] Do not allow starting selection drags when selection views are not visible
     4        https://bugs.webkit.org/show_bug.cgi?id=196686
     5        <rdar://problem/49399192>
     6
     7        Reviewed by Tim Horton.
     8
     9        Adjust some existing API tests to make the web view become first responder before trying to begin dragging, and
     10        also add some new API tests to cover scenarios where the web view is not first responder.
     11
     12        * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
     13        (TestWebKitAPI::TEST):
     14        * TestWebKitAPI/cocoa/DragAndDropSimulator.h:
     15
     16        Add a switch to optionally make the web view first responder when starting the simulated drag.
     17
     18        * TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
     19        (-[DragAndDropSimulator initWithWebView:]):
     20        (-[DragAndDropSimulator runFrom:to:additionalItemRequestLocations:]):
     21
    1222019-04-08  Justin Fan  <justin_fan@apple.com>
    223
  • trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm

    r242530 r244056  
    431431}
    432432
     433TEST(DragAndDropTests, DoNotPerformSelectionDragWhenNotFirstResponder)
     434{
     435    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
     436    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
     437    [simulator setShouldBecomeFirstResponder:NO];
     438
     439    [webView synchronouslyLoadTestPageNamed:@"selected-text-and-textarea"];
     440    [simulator runFrom:CGPointMake(160, 100) to:CGPointMake(160, 300)];
     441
     442    EXPECT_WK_STREQ("", [webView stringByEvaluatingJavaScript:@"destination.value"]);
     443}
     444
     445TEST(DragAndDropTests, CanDragImageWhenNotFirstResponder)
     446{
     447    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
     448    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
     449    [simulator setShouldBecomeFirstResponder:NO];
     450
     451    [webView synchronouslyLoadTestPageNamed:@"image-and-contenteditable"];
     452    [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(100, 250)];
     453
     454    NSURL *droppedImageURL = [NSURL URLWithString:[webView stringByEvaluatingJavaScript:@"editor.querySelector('img').src"]];
     455    EXPECT_WK_STREQ("blob", droppedImageURL.scheme);
     456}
     457
    433458TEST(DragAndDropTests, ContentEditableMoveParagraphs)
    434459{
  • trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h

    r242339 r244056  
    9696@property (nonatomic) BOOL allowsFocusToStartInputSession;
    9797@property (nonatomic) BOOL shouldEnsureUIApplication;
     98@property (nonatomic) BOOL shouldBecomeFirstResponder;
    9899@property (nonatomic) BOOL shouldAllowMoveOperation;
    99100@property (nonatomic, strong) NSArray *externalItemProviders;
  • trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm

    r243519 r244056  
    344344        _webView = webView;
    345345        _shouldEnsureUIApplication = NO;
     346        _shouldBecomeFirstResponder = YES;
    346347        _shouldAllowMoveOperation = YES;
    347348        [_webView setUIDelegate:self];
     
    416417        UIApplicationInstantiateSingleton([DragAndDropSimulatorApplication class]);
    417418
     419    if (_shouldBecomeFirstResponder)
     420        [_webView becomeFirstResponder];
     421
    418422    [self _resetSimulatedState];
    419423
Note: See TracChangeset for help on using the changeset viewer.