Bug 67822

Summary: PlatformGestureEvent::handleGestureEvent should hit test while dispatching Scroll* events.
Product: WebKit Reporter: Robert Kroeger <rjkroege>
Component: UI EventsAssignee: Robert Kroeger <rjkroege>
Status: RESOLVED INVALID    
Severity: Normal CC: abarth, dglazkov, donggwan.kim, fsamuel, gustavo.noronha, gustavo, jamesr, rniwa, scottbyer, varunjain, wjmaclean, xan.lopez
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 66272, 80201, 80311    
Bug Blocks: 73489    
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch jamesr: review-, buildbot: commit-queue-

Robert Kroeger
Reported 2011-09-08 17:41:26 PDT
Per the FIXME in the code: EventHandler::handleGestureEvent should hit test and send ScrollBeginType, ScrollUpdateType and ScrollEndType events to the correct subframe rather than always sending gestures to the main frame only. It should also ensure that if a frame gets a gesture begin gesture, it gets the corresponding end gesture as well.
Attachments
Patch (20.58 KB, patch)
2011-09-09 12:37 PDT, Robert Kroeger
no flags
Patch (38.73 KB, patch)
2011-10-20 14:56 PDT, Robert Kroeger
no flags
Patch (42.57 KB, patch)
2011-10-26 15:40 PDT, Robert Kroeger
no flags
Patch (43.25 KB, patch)
2011-10-27 14:47 PDT, Robert Kroeger
no flags
Patch (59.23 KB, patch)
2011-12-23 12:41 PST, Robert Kroeger
no flags
Patch (62.31 KB, patch)
2012-01-05 12:55 PST, Robert Kroeger
no flags
Patch (62.57 KB, patch)
2012-01-05 14:10 PST, Robert Kroeger
no flags
Patch (62.60 KB, patch)
2012-01-05 14:44 PST, Robert Kroeger
no flags
Patch (79.60 KB, patch)
2012-03-01 13:26 PST, Robert Kroeger
jamesr: review-
buildbot: commit-queue-
Robert Kroeger
Comment 1 2011-09-09 12:37:53 PDT
Robert Kroeger
Comment 2 2011-09-09 12:41:53 PDT
Hi Adam, The attached patch works for Chrome but still needs some cleanup and multuple layout tests. I'm hoping you could give me some high-level feedback on the approach and suggest who I should get to review the final version. Thanks.
Adam Barth
Comment 3 2011-09-09 17:04:34 PDT
Comment on attachment 106903 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=106903&action=review I didn't review the whole patch, but this needs a bunch of work. I'm sorry that I don't have time to help you with this patch. You might try dglazkov. He's done a bunch of work with event handling. > Source/WebCore/page/EventHandler.cpp:2206 > + Document* doc = m_frame->document(); This looks dangerous. This point could become junk while dispatching events. It's probably best to grab the document point from the frame each time you need it. > Source/WebCore/page/EventHandler.cpp:2226 > + if (m_gestureEventWidgetTarget.get() && m_gestureEventWidgetTarget->refCount() > 1 && passGestureEventToWidget(gestureEvent, m_gestureEventWidgetTarget.get())) Crazy. It's very rare to branch on the refCount of an object. I suspect this isn't the right thing to do. > Source/WebCore/page/EventHandler.cpp:2228 > + if (m_gestureEventWidgetTarget.get() && m_gestureEventWidgetTarget->hasOneRef()) No need to call get() to convert a RefPtr to a bool. > Source/WebCore/page/EventHandler.cpp:2232 > + RenderLayer* layer = ((RenderBox*)m_gestureTargetNode->renderer())->layer(); Please use C++ style casts. How do you know its a RenderBox?? > Source/WebCore/page/EventHandler.cpp:2249 > + LayoutPoint vPoint = view->windowToContents(gestureEvent.position()); vPoint => please use full words when naming variables. > Source/WebCore/page/EventHandler.cpp:2251 > + Node* node; > + bool isOverWidget; Please initialize scalars. > Source/WebCore/page/EventHandler.cpp:2257 > + node = result.innerNode(); Why not just declare node at this point? Then we don't need to worry about someone using it between when it is declared and when it is initialized. Also, consider taking a reference to the node so that it doesn't get deallocated out from under you. > Source/WebCore/page/EventHandler.cpp:2260 > + if (node) { Prefer early return. > Source/WebCore/page/EventHandler.cpp:2269 > + node = node->shadowAncestorNode(); Why are we re-using the same variable? /me is confused. > Source/WebCore/page/EventHandler.cpp:2281 > + while (target && !target->isRoot()) { > + if (target->isBox()) { > + RenderBox* rb = (RenderBox*)target; > + if (rb->canBeScrolledAndHasScrollableArea()) { > + m_gestureTargetNode = rb->node(); > + rb->layer()->handleGestureEvent(gestureEvent); > + return true; // FIXME: Prove that this is correct. > + } > + } > + target = target->parent(); This looks like a lot of render tree manipulation to be doing outside of the rendering directory.
Robert Kroeger
Comment 4 2011-09-12 13:00:26 PDT
Hi Adam, Thanks for the useful feedback. I know it still needs a lot of work -- I was looking for this kind of early feedback that will stop me going down the wrong rabbit hole. I'll ask Dimitri about taking a look but maybe you'd have time for some quick follow up questions to your review -- inlined in your comments.
Adam Barth
Comment 5 2011-09-12 13:54:21 PDT
> inlined in your comments. I don't see your comments. You might need to "publish" them for other folks to be able to see them.
Robert Kroeger
Comment 6 2011-09-13 13:04:37 PDT
(In reply to comment #5) > > inlined in your comments. > > I don't see your comments. You might need to "publish" them for other folks to be able to see them. Indeed. I forgot to hit publish in another browser window.
Robert Kroeger
Comment 7 2011-09-13 14:58:23 PDT
Comment on attachment 106903 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=106903&action=review >> Source/WebCore/page/EventHandler.cpp:2226 >> + if (m_gestureEventWidgetTarget.get() && m_gestureEventWidgetTarget->refCount() > 1 && passGestureEventToWidget(gestureEvent, m_gestureEventWidgetTarget.get())) > > Crazy. It's very rare to branch on the refCount of an object. I suspect this isn't the right thing to do. my aim was to deal with the case where JS execution disappeared the node between successive PlatformGestureEvents. Is it reasonable to follow the example of how m_latchedWheelEventNode is handled (I plan on having a layout test for the case of ScrollStart ScrollUpdate* <remove target> ScrollEnd) >> Source/WebCore/page/EventHandler.cpp:2232 >> + RenderLayer* layer = ((RenderBox*)m_gestureTargetNode->renderer())->layer(); > > Please use C++ style casts. How do you know its a RenderBox?? Because I only set m_gestureTargetNode if its renderer() was a RenderBox instance. >> Source/WebCore/page/EventHandler.cpp:2269 >> + node = node->shadowAncestorNode(); > > Why are we re-using the same variable? /me is confused. I'll ask Dimitri about the correct way of shadowdom. I was copying from EventHandler::handleWheelEvent. >> Source/WebCore/page/EventHandler.cpp:2281 >> + target = target->parent(); > > This looks like a lot of render tree manipulation to be doing outside of the rendering directory. Having a GestureEventWithHitTestResult similar to MouseEventWithHitTestResult would be the right encapsulation of this search? It would reside in /rendering and would appear to get most/all of the necessary functionality from HitTestResult.
Robert Kroeger
Comment 8 2011-10-20 14:56:54 PDT
Robert Kroeger
Comment 9 2011-10-20 14:59:22 PDT
Hi Dimitri, per Adam's suggestion, could you have a look at this and give me some feedback on approach/further issues to address?
Dimitri Glazkov (Google)
Comment 10 2011-10-21 11:16:24 PDT
Comment on attachment 111852 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=111852&action=review > Source/WebCore/page/EventHandler.cpp:2225 > + bool isOverWidget = result.isOverWidget(); This can move below the !node check. > Source/WebCore/page/EventHandler.cpp:2238 > + node = node->shadowAncestorNode(); What are you trying to do there? Can you explain a bit more? > Source/WebCore/page/EventHandler.cpp:2259 > + RenderBox* enclosingBox = renderer->enclosingBox(); > + while (enclosingBox && !enclosingBox->canBeScrolledAndHasScrollableArea()) { > + if (!enclosingBox->parent()) > + return false; > + enclosingBox = enclosingBox->parent()->enclosingBox(); > + } > + > + if (enclosingBox && enclosingBox->node() != enclosingBox->document()) { > + RenderLayer* layer = enclosingBox->layer(); > + if (layer) { > + layer->handleGestureEvent(gestureEvent); > + return true; > + } > + } looks like this should be something like enclosingScrollableLayer. I bet we already have code that does this. > Source/WebCore/page/EventHandler.cpp:2271 > +// REVIEWER: I hunted for something like this in wtf::. Does it exist? If not, > +// is it worth adding a generic version? > +// Helper to auto-unlatch on end of scope. Can you explain why you would need something like this?
Robert Kroeger
Comment 11 2011-10-26 15:07:49 PDT
Comment on attachment 111852 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=111852&action=review >> Source/WebCore/page/EventHandler.cpp:2225 >> + bool isOverWidget = result.isOverWidget(); > > This can move below the !node check. done, next patch. >> Source/WebCore/page/EventHandler.cpp:2238 >> + node = node->shadowAncestorNode(); > > What are you trying to do there? Can you explain a bit more? I was following along with how mouse wheel events would seem to be sent into the shadow DOM -- http://codesearch.google.com/codesearch#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/page/EventHandler.cpp&exact_package=chromium&q=EventHandler&type=cs&l=2184 was the inspiration. Reasonable or foolish? >> Source/WebCore/page/EventHandler.cpp:2259 >> + } > > looks like this should be something like enclosingScrollableLayer. I bet we already have code that does this. I tried using enclosingScrollableLayer and went on a voyage of discovery. In particular: it does not want to be used from EventHandler. (I would think I was attempting to create a layering violation.) So, I ended up dispatching the events a different way that seems "more correct" -- the code ended up shorter and simpler in the next patch. >> Source/WebCore/page/EventHandler.cpp:2271 >> +// Helper to auto-unlatch on end of scope. > > Can you explain why you would need something like this? to always clear the RefPtr on leaving the enclosing scope in handleGestureEvent so that I don't preserve an unnecessary reference to the target node for the Scroll* sequence after the concluding ScrollEndType event.
Robert Kroeger
Comment 12 2011-10-26 15:40:02 PDT
Robert Kroeger
Comment 13 2011-10-26 15:47:19 PDT
Please take another look. Notes: * rniwa: added per Dimitri's suggestion. Would you be a more appropriate reviewer for this change? * patch is not complete. Am looking for feedback on the approach/C++ code. The layout tests are not done yet to my satisfaction (they so far only show that the implementation is correct on Chromium) and there are still some missing bits for non-Chromium code paths.
Ryosuke Niwa
Comment 14 2011-10-26 16:30:23 PDT
Comment on attachment 112607 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=112607&action=review > Source/WebCore/ChangeLog:7 > + You need to explain what kind of changes you're making. > Source/WebCore/ChangeLog:16 > + (WebCore::wheelGranularityToScrollGranularity): > + Helper method. > + (WebCore::scrollNode): > + Refactored. Please put the description on the same line as the function name after :. > Source/WebCore/page/EventHandler.cpp:178 > +static inline bool gestureNode(const PlatformGestureEvent& e, Node* node) Please don't use one-letter variable like e. > Source/WebCore/page/EventHandler.cpp:2238 > +bool EventHandler::passGestureEventToWidgetHelper(PassRefPtr<Node> targetNode, const PlatformGestureEvent& gestureEvent, const HitTestResult& result) Why does this function need to be a member function of Event Handler? It can be a static non-member function, no? Why is this function called "helper"? We need a more descriptive name. > Source/WebCore/page/EventHandler.cpp:2249 > + if (isOverWidget && target && target->isWidget()) { > + Widget* widget = toRenderWidget(target)->widget(); > + if (widget && passGestureEventToWidget(gestureEvent, widget)) We prefer early exit over nested ifs. > Source/WebCore/page/EventHandler.cpp:2255 > +bool EventHandler::passGestureEventToFameView(const PlatformGestureEvent& gestureEvent) Ditto. Also, typo: Fame -> Frame. > Source/WebCore/page/EventHandler.cpp:2267 > +// Helper to always unlatch target node on leaving scope. > +class Unlatcher { > +public: What's the point of this class? I don't understand what you mean by "unlatch". Can't you just use RefPtr? What's the point of wrapping it with a class? > Source/WebCore/page/EventHandler.cpp:2283 > + Document* doc = m_frame->document(); Please don't use abbreviations like doc. > Source/WebCore/page/EventHandler.cpp:2292 > + LayoutPoint vPoint = view->windowToContents(gestureEvent.position()); What does v stand for? Please don't use abbreviations. > Source/WebCore/page/EventHandler.cpp:2303 > + // FIXME: Refactor this code to not hit test multiple times by using the code > + // written for scroll. Why are you splitting this comment into 2 lines? It fit the line perfectly. > Source/WebCore/page/EventHandler.cpp:2320 > + bool xscroll = node && scrollNode(gestureEvent.deltaX(), ScrollByPixel, ScrollLeft, ScrollRight, node, (Node**)0); Nit: camelCase. xScroll, and s/(Node**)0/0/; > Source/WebCore/page/EventHandler.cpp:2321 > + bool yscroll = node && scrollNode(gestureEvent.deltaY(), ScrollByPixel, ScrollUp, ScrollDown, node, (Node**)0); Ditto. > Source/WebCore/platform/ScrollAnimator.cpp:138 > + float deltaX = (event.deltaX() < 0.f) ? max(event.deltaX(), -float(maxForwardScrollDelta.width())) : min(event.deltaX(), float(maxBackwardScrollDelta.width())); Nit: two spaces before -float. Also, please use C++-style casting e.g. static_cast<float>(). > Source/WebCore/rendering/RenderBox.cpp:677 > + fprintf(stderr, "RenderBox::gesture\n"); What's up with this fprintf? > Source/WebCore/rendering/RenderBox.cpp:678 > + RenderLayer* layer = layer(); I'm surprised that this didn't cause a compilation error. r- because this is certainly going to cause a compilation failure on one of ports.
Robert Kroeger
Comment 15 2011-10-27 14:47:33 PDT
Robert Kroeger
Comment 16 2011-10-27 14:49:31 PDT
Comment on attachment 112607 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=112607&action=review >> Source/WebCore/ChangeLog:7 >> + > > You need to explain what kind of changes you're making. done in p4 >> Source/WebCore/ChangeLog:16 >> + Refactored. > > Please put the description on the same line as the function name after :. done in p4 >> Source/WebCore/page/EventHandler.cpp:178 >> +static inline bool gestureNode(const PlatformGestureEvent& e, Node* node) > > Please don't use one-letter variable like e. done, p4 >> Source/WebCore/page/EventHandler.cpp:2238 >> +bool EventHandler::passGestureEventToWidgetHelper(PassRefPtr<Node> targetNode, const PlatformGestureEvent& gestureEvent, const HitTestResult& result) > > Why does this function need to be a member function of Event Handler? It can be a static non-member function, no? > > Why is this function called "helper"? We need a more descriptive name. done, p4 >> Source/WebCore/page/EventHandler.cpp:2249 >> + if (widget && passGestureEventToWidget(gestureEvent, widget)) > > We prefer early exit over nested ifs. done, p4 >> Source/WebCore/page/EventHandler.cpp:2255 >> +bool EventHandler::passGestureEventToFameView(const PlatformGestureEvent& gestureEvent) > > Ditto. Also, typo: Fame -> Frame. done, p4. autocomplete for the non-win. >> Source/WebCore/page/EventHandler.cpp:2267 >> +public: > > What's the point of this class? I don't understand what you mean by "unlatch". > > Can't you just use RefPtr? What's the point of wrapping it with a class? Background: handleGestureEvent receives a sequence of ScrollDownType, ScrollUpdateType*, ScrollEndType PGE sub-events. The ScrollDownType event chooses the target node and "latches" it in m_gestureTargetNode. Why "latch": from the language in the WheelEvent handling code. The following ScrollUpdateType and ScrollEndType events all go to the original latching node (assuming it still exists.) The latching node (stored in m_gestureTargetNode) should always be cleared on an ScrollEndType event even in the presence of early return from the containing block. Unlatcher does that. If there is a better way, please let me know. >> Source/WebCore/page/EventHandler.cpp:2283 >> + Document* doc = m_frame->document(); > > Please don't use abbreviations like doc. fixed p4 >> Source/WebCore/page/EventHandler.cpp:2292 >> + LayoutPoint vPoint = view->windowToContents(gestureEvent.position()); > > What does v stand for? Please don't use abbreviations. done in p4 >> Source/WebCore/page/EventHandler.cpp:2303 >> + // written for scroll. > > Why are you splitting this comment into 2 lines? It fit the line perfectly. done in p4 >> Source/WebCore/page/EventHandler.cpp:2320 >> + bool xscroll = node && scrollNode(gestureEvent.deltaX(), ScrollByPixel, ScrollLeft, ScrollRight, node, (Node**)0); > > Nit: camelCase. xScroll, and s/(Node**)0/0/; done in p4. yScroll too. >> Source/WebCore/platform/ScrollAnimator.cpp:138 >> + float deltaX = (event.deltaX() < 0.f) ? max(event.deltaX(), -float(maxForwardScrollDelta.width())) : min(event.deltaX(), float(maxBackwardScrollDelta.width())); > > Nit: two spaces before -float. Also, please use C++-style casting e.g. static_cast<float>(). done, p4 >> Source/WebCore/rendering/RenderBox.cpp:677 >> + fprintf(stderr, "RenderBox::gesture\n"); > > What's up with this fprintf? removed. >> Source/WebCore/rendering/RenderBox.cpp:678 >> + RenderLayer* layer = layer(); > > I'm surprised that this didn't cause a compilation error. r- because this is certainly going to cause a compilation failure on one of ports. it did. fixed in p4
Robert Kroeger
Comment 17 2011-10-27 14:50:32 PDT
Please take another look.
Robert Kroeger
Comment 18 2011-12-23 12:41:45 PST
Early Warning System Bot
Comment 19 2011-12-23 14:04:02 PST
Gyuyoung Kim
Comment 20 2011-12-23 14:04:55 PST
Sam Weinig
Comment 21 2011-12-23 14:48:39 PST
Comment on attachment 120475 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=120475&action=review > Source/WebCore/platform/ScrollAnimator.h:120 > +#if ENABLE(GESTURE_EVENTS) > + int m_gestureEventTestRecord; > +#endif It doesn't seem like a good idea to be adding state to the implementation that is only used for testing. Perhaps I misunderstand what this is being used for.
Gustavo Noronha (kov)
Comment 22 2011-12-23 15:25:14 PST
Collabora GTK+ EWS bot
Comment 23 2011-12-23 16:07:00 PST
Robert Kroeger
Comment 24 2012-01-03 07:29:11 PST
Comment on attachment 120475 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=120475&action=review >> Source/WebCore/platform/ScrollAnimator.h:120 >> +#endif > > It doesn't seem like a good idea to be adding state to the implementation that is only used for testing. Perhaps I misunderstand what this is being used for. Sam: This is what it was for. Since gesture events don't all reach JavaScript, I needed some way to prove that the implementation was correct. A solution that occurred to me would be to create a testing subclass of ScrollAnimator for use in DumpRenderTree. Does this sound reasonable? Or is there an easier way? BTW: given that this patch addresses your FIXME, do you have any other general advice for improving the patch?
Robert Kroeger
Comment 25 2012-01-05 12:55:11 PST
Robert Kroeger
Comment 26 2012-01-05 12:59:37 PST
Ryosuke: could you take another look please? I've addressed weinig's comment but not perhaps in the nicest of ways.
Gyuyoung Kim
Comment 27 2012-01-05 13:07:04 PST
Early Warning System Bot
Comment 28 2012-01-05 13:07:31 PST
Robert Kroeger
Comment 29 2012-01-05 14:10:41 PST
Robert Kroeger
Comment 30 2012-01-05 14:12:29 PST
Improved include guards.
Gyuyoung Kim
Comment 31 2012-01-05 14:38:29 PST
Robert Kroeger
Comment 32 2012-01-05 14:44:36 PST
Gustavo Noronha (kov)
Comment 33 2012-01-05 21:08:27 PST
James Robinson
Comment 34 2012-02-21 20:45:42 PST
Comment on attachment 121332 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=121332&action=review At least some of the code this patch is patching was deleted a bit back, so this doesn't apply. If we plan to proceed with this patch I think you need to figure out how it fits in now. > Source/WebCore/platform/ScrollAnimator.cpp:136 > +void ScrollAnimator::handleGestureEvent(const PlatformGestureEvent& event) this was deleted in http://trac.webkit.org/changeset/107823
Robert Kroeger
Comment 35 2012-03-01 13:26:50 PST
Build Bot
Comment 36 2012-03-01 13:48:06 PST
James Robinson
Comment 37 2012-03-01 14:21:57 PST
Comment on attachment 129738 [details] Patch We discussed this offline. I think we'll be better off if ScrollView / ScrollAnimator / etc do not have to be explicitly aware of GestureEvents, but that we translate the gesture into a logical scroll earlier in the pipeline and then pass that through.
Robert Kroeger
Comment 38 2012-03-01 17:31:11 PST
per a discussion with jamesr: I'm going to simplify this patch and divide it into three sub-patches that: * improve chromium EventSender::gestureEvent to send fully-populated GestureScroll* gestures. * show that interim version in ToT using mouse wheel events works correctly for GestureScrollUpdate messages. * change to EventHandler::handleGestureEvent to dispatch fling as an additional kind of scroll rather than the approach that I took here. I'll leave this bug to track.
Robert Kroeger
Comment 39 2012-11-30 09:52:10 PST
Obsolete bug.
Note You need to log in before you can comment on or make changes to this bug.