Bug 98173 - Allow EventHandler to handle longpress gestures, including longpress selection on Android.
Summary: Allow EventHandler to handle longpress gestures, including longpress selectio...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Oli Lan
URL:
Keywords:
Depends on:
Blocks: 66687
  Show dependency treegraph
 
Reported: 2012-10-02 10:11 PDT by Oli Lan
Modified: 2012-10-05 13:45 PDT (History)
10 users (show)

See Also:


Attachments
Patch (6.03 KB, patch)
2012-10-02 10:16 PDT, Oli Lan
no flags Details | Formatted Diff | Diff
Patch (10.22 KB, patch)
2012-10-03 07:47 PDT, Oli Lan
no flags Details | Formatted Diff | Diff
Patch (10.35 KB, patch)
2012-10-03 10:12 PDT, Oli Lan
no flags Details | Formatted Diff | Diff
Patch (11.14 KB, patch)
2012-10-04 07:02 PDT, Oli Lan
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Oli Lan 2012-10-02 10:11:58 PDT
[chromium] Allow long press to select word on Android.
Comment 1 Oli Lan 2012-10-02 10:16:40 PDT
Created attachment 166706 [details]
Patch
Comment 2 Ryosuke Niwa 2012-10-02 10:21:44 PDT
Comment on attachment 166706 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166706&action=review

> Source/WebKit/chromium/src/WebViewImpl.cpp:4077
> +    FrameSelection* fs = focusedFrame->selection();

Please don't use abbreviations like fs.

> Source/WebKit/chromium/src/WebViewImpl.cpp:4081
> +    if (node->renderer() && !fs->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink()
> +        && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) {
> +        VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint()));
> +        WebFrameImpl::selectWordAroundPosition(focusedFrame, pos);

This code looks fishy to me. Why isn't this in EventHandler.cpp?
In particular, we should be using canMouseDownStartSelect and share most of code with selectClosestWordFromMouseEvent.
Comment 3 Oli Lan 2012-10-03 07:47:46 PDT
Created attachment 166892 [details]
Patch
Comment 4 Oli Lan 2012-10-03 07:50:59 PDT
Thanks for the review. The second patch changes this to be implemented fully within EventHandler. The code to perform the selection is now shared as much as possible with selectClosestWordFromMouseEvent.

I did not call canMouseDownStartSelect for this as that seems to be concerned with preventing mouse drags from starting selection when there is a draggable element.
Comment 5 WebKit Review Bot 2012-10-03 10:00:59 PDT
Comment on attachment 166892 [details]
Patch

Attachment 166892 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/14131721

New failing tests:
fast/events/touch/gesture/context-menu-on-two-finger-tap.html
Comment 6 Oli Lan 2012-10-03 10:12:06 PDT
Created attachment 166915 [details]
Patch
Comment 7 Ryosuke Niwa 2012-10-03 12:11:58 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

Excellent! This patch looks much, much better.

> Source/WebCore/page/EventHandler.cpp:455
> +        selectClosestWordFromHitTestResult(result.hitTestResult(), (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);

This is a really long time. I would split into two lines (make sure to add curly brackets around the if statement in that case).
Comment 8 WebKit Review Bot 2012-10-03 12:35:32 PDT
Comment on attachment 166915 [details]
Patch

Attachment 166915 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/14118975

New failing tests:
fast/events/touch/gesture/context-menu-on-two-finger-tap.html
Comment 9 Robert Kroeger 2012-10-03 15:25:58 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

> Source/WebCore/page/EventHandler.cpp:2523
> +        return handleGestureLongPress(gestureEvent);

why do this here instead of in WebViewImpl? Am curious.

> Source/WebKit/chromium/src/WebViewImpl.cpp:-732
> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);

As per the failing layout test, this changes breaks touch summoning of context menus on CrOS/Windows Chrome. Please consider putting this back and introducing a new different gesture event for text editing initiation. I suggest GestureStartTextSelection.
Comment 10 Ryosuke Niwa 2012-10-03 15:32:02 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

> Source/WebKit/chromium/src/WebViewImpl.cpp:732
> +        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);

Oh oops, this is going to fire a gesture event :(
Comment 11 Oli Lan 2012-10-03 16:05:22 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

>> Source/WebKit/chromium/src/WebViewImpl.cpp:-732
>> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
> 
> As per the failing layout test, this changes breaks touch summoning of context menus on CrOS/Windows Chrome. Please consider putting this back and introducing a new different gesture event for text editing initiation. I suggest GestureStartTextSelection.

"Start Text Selection" isn't a gesture though, is it? It's the result of a gesture for us, but a gesture should be something the user does, like tap or longpress, or two-finger tap.

The failing test is to do with two-finger-tap. I'll check to see if this change has had any unintended effects on that.

This change should still allow context menus to work, as sendContextMenuEventForGesture is now called by handleGestureLongPress, which is called by handleGestureEvent. The code to perform selection is OS(ANDROID) only.

>> Source/WebKit/chromium/src/WebViewImpl.cpp:732
>> +        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);
> 
> Oh oops, this is going to fire a gesture event :(

This will have the effect that the longpress gesture goes to the node in the same way that a tap gesture already does. If it's not swallowed, then the result will be the same as before, in that sendContextMenuEventForGesture will be called. Is that not ok?
Comment 12 Varun Jain 2012-10-03 16:26:32 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

>>> Source/WebKit/chromium/src/WebViewImpl.cpp:-732
>>> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
>> 
>> As per the failing layout test, this changes breaks touch summoning of context menus on CrOS/Windows Chrome. Please consider putting this back and introducing a new different gesture event for text editing initiation. I suggest GestureStartTextSelection.
> 
> "Start Text Selection" isn't a gesture though, is it? It's the result of a gesture for us, but a gesture should be something the user does, like tap or longpress, or two-finger tap.
> 
> The failing test is to do with two-finger-tap. I'll check to see if this change has had any unintended effects on that.
> 
> This change should still allow context menus to work, as sendContextMenuEventForGesture is now called by handleGestureLongPress, which is called by handleGestureEvent. The code to perform selection is OS(ANDROID) only.

I think the #if should be in WebViewImpl and not EventHandler. For instance, why (for android) is m_contextMenuAllowed set to true on long press when no context menu is shown.
Comment 13 Oli Lan 2012-10-04 02:28:24 PDT
Comment on attachment 166915 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review

>>>> Source/WebKit/chromium/src/WebViewImpl.cpp:-732
>>>> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
>>> 
>>> As per the failing layout test, this changes breaks touch summoning of context menus on CrOS/Windows Chrome. Please consider putting this back and introducing a new different gesture event for text editing initiation. I suggest GestureStartTextSelection.
>> 
>> "Start Text Selection" isn't a gesture though, is it? It's the result of a gesture for us, but a gesture should be something the user does, like tap or longpress, or two-finger tap.
>> 
>> The failing test is to do with two-finger-tap. I'll check to see if this change has had any unintended effects on that.
>> 
>> This change should still allow context menus to work, as sendContextMenuEventForGesture is now called by handleGestureLongPress, which is called by handleGestureEvent. The code to perform selection is OS(ANDROID) only.
> 
> I think the #if should be in WebViewImpl and not EventHandler. For instance, why (for android) is m_contextMenuAllowed set to true on long press when no context menu is shown.

Longpress on android can show a context menu, for example on a link or an image. Selection of text only occurs if the longpress was on non-link text.

The reason for the failing test is that I didn't notice that WebInputEvent::GestureTwoFingerTap uses the same code path as GestureLongPress in WebViewImpl::handleGestureEvent, whereas EventHandler::handleGestureEvent doesn't handle two finger tap so this change disables that gesture. I will restore two finger tap in a new patch.
Comment 14 Oli Lan 2012-10-04 07:02:33 PDT
Created attachment 167097 [details]
Patch
Comment 15 Oli Lan 2012-10-04 07:04:35 PDT
The last patch restores GestureTwoFingerTap handling to how it was (except without the detectContentOnTouch call which is Android-only and shouldn't be called for a two-finger tap).

The layout test context-menu-on-two-finger-tap.html should now pass.
Comment 16 Varun Jain 2012-10-04 09:26:13 PDT
(In reply to comment #13)
> (From update of attachment 166915 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=166915&action=review
> 
> >>>> Source/WebKit/chromium/src/WebViewImpl.cpp:-732
> >>>> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
> >>> 
> >>> As per the failing layout test, this changes breaks touch summoning of context menus on CrOS/Windows Chrome. Please consider putting this back and introducing a new different gesture event for text editing initiation. I suggest GestureStartTextSelection.
> >> 
> >> "Start Text Selection" isn't a gesture though, is it? It's the result of a gesture for us, but a gesture should be something the user does, like tap or longpress, or two-finger tap.
> >> 
> >> The failing test is to do with two-finger-tap. I'll check to see if this change has had any unintended effects on that.
> >> 
> >> This change should still allow context menus to work, as sendContextMenuEventForGesture is now called by handleGestureLongPress, which is called by handleGestureEvent. The code to perform selection is OS(ANDROID) only.
> > 
> > I think the #if should be in WebViewImpl and not EventHandler. For instance, why (for android) is m_contextMenuAllowed set to true on long press when no context menu is shown.
> 
> Longpress on android can show a context menu, for example on a link or an image. Selection of text only occurs if the longpress was on non-link text.
> 
> The reason for the failing test is that I didn't notice that WebInputEvent::GestureTwoFingerTap uses the same code path as GestureLongPress in WebViewImpl::handleGestureEvent, whereas EventHandler::handleGestureEvent doesn't handle two finger tap so this change disables that gesture. I will restore two finger tap in a new patch.

I was not talking about the failing test at all. My concern is that for android, we are setting the state of context menu allowed to true but not showing the context menu in some cases. This seems wrong. It appears to me that a script listening to selection change will be able to invoke context menu since WebViewImpl will allow it.
FWIW, I am not a reviewer :) so you can totally ignore my comments if the reviewers agree to this.
Comment 17 Ryosuke Niwa 2012-10-04 10:28:07 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

> Source/WebKit/chromium/src/WebViewImpl.cpp:726
> +        m_contextMenuAllowed = true;
> +        PlatformGestureEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
> +        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
> +        m_contextMenuAllowed = false;

I agree with Varun that it's strange to set m_contextMenuAllowed true and then not show the context menu.
On the other hand, I don't understand the value of having this boolean variable in the first place.
Comment 18 Oli Lan 2012-10-04 10:39:41 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

>> Source/WebKit/chromium/src/WebViewImpl.cpp:726
>> +        m_contextMenuAllowed = false;
> 
> I agree with Varun that it's strange to set m_contextMenuAllowed true and then not show the context menu.
> On the other hand, I don't understand the value of having this boolean variable in the first place.

m_contextMenuAllowed is only read in ContextMenuClientImpl::getCustomMenuFromDefaultItems, where the aim is to ensure that the context menu is only shown in response to user input.

I'd argue that, as longpress is a gesture that can show a context menu, it's correct for m_contextMenuAllowed to be true when a longpress is handled by the EventHandler, regardless of whether or not the default handling will show the menu.
Comment 19 Robert Kroeger 2012-10-04 11:44:08 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

> Source/WebCore/page/EventHandler.cpp:433
> +void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)

this code looks a lot like WebFrameImpl::selectWordAroundPosition Is there an opportunity to remove some duplicate code especially since selectClosestWord* doesn't seem to be used anywhere else yet?

> Source/WebCore/page/EventHandler.cpp:2575
> +#if OS(ANDROID)

I'd prefer it if you added a flag or a different kind of event instead of the #ifdef.
Comment 20 Ryosuke Niwa 2012-10-04 11:50:23 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

>> Source/WebCore/page/EventHandler.cpp:2575
>> +#if OS(ANDROID)
> 
> I'd prefer it if you added a flag or a different kind of event instead of the #ifdef.

In this case, ifdef is better.
Comment 21 Oli Lan 2012-10-05 05:35:41 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

>> Source/WebCore/page/EventHandler.cpp:433
>> +void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
> 
> this code looks a lot like WebFrameImpl::selectWordAroundPosition Is there an opportunity to remove some duplicate code especially since selectClosestWord* doesn't seem to be used anywhere else yet?

selectClosestWordFromMouseEvent and selectClosestWordOrLinkFromMouseEvent are preexisting methods, and are used when double-clicks are handled and for selecting a word on Mac when a context menu is generated. This method selectClosestWordFromHitTestResult was added just to make the code no longer dependent on a mouse event so we could use it from a touch gesture - as you can see it mostly uses the previous code from selectClosestWordFromMouseEvent.

My first attempt at this change (patch 1) was in WebViewImpl and used selectWordAroundPosition, but on rniwa's suggestion I moved it into EventHandler. I think this it makes sense for it to be in EventHandler, seeing as it's to do with handling gesture events.
Comment 22 Oli Lan 2012-10-05 10:15:19 PDT
Ryosuke (and other reviewers), what do you think of the latest version of this patch? Does it need further changes?
Comment 23 Ryosuke Niwa 2012-10-05 12:11:09 PDT
Comment on attachment 167097 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=167097&action=review

> Source/WebKit/chromium/src/WebViewImpl.cpp:743
> -        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->sendContextMenuEventForGesture(platformEvent);
> +        eventSwallowed = mainFrameImpl()->frame()->eventHandler()->handleGestureEvent(platformEvent);

handleGestureEvent is going to fire a gesture event. Why is that okay?
If that's intended, we should have a test for that, right? Or am I misunderstanding something?
Comment 24 Adam Barth 2012-10-05 12:13:43 PDT
> handleGestureEvent is going to fire a gesture event. Why is that okay?
> If that's intended, we should have a test for that, right? Or am I misunderstanding something?

I don't think we expose gesture events to the web.  We might do that in the future, depending on how the touch events / pointer events / gesture events discussion plays out in the standards world.
Comment 25 Ryosuke Niwa 2012-10-05 12:28:18 PDT
Adam clarified his comment. If we look at GestureEvent::create, we see that we only instantiate the event for a subset of gestures.
Comment 26 WebKit Review Bot 2012-10-05 13:45:16 PDT
Comment on attachment 167097 [details]
Patch

Clearing flags on attachment: 167097

Committed r130547: <http://trac.webkit.org/changeset/130547>
Comment 27 WebKit Review Bot 2012-10-05 13:45:21 PDT
All reviewed patches have been landed.  Closing bug.