Source/WebCore/ChangeLog

 12014-06-30 Peyton Randolph <prandolph@apple.com>
 2
 3 Add link long-press event handling using a timer.
 4 https://bugs.webkit.org/show_bug.cgi?id=134262
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 This patch adds the link long-press gesture's event handling. There are three events we care about: starting the
 9 long-press [start], triggering the long-press [trigger], and cancelling the long-press before or after
 10 triggering [cancel].
 11
 12 The general flow of the event is as follows (the event triggered at a step is placed in square brackets):
 13
 14 - [start] The user mouses down over a link.
 15 - [trigger] The user keeps the mouse pressed on that link without moving their mouse too much for longer than
 16 the specified long-press duration.
 17 - The user releases their mouse press.
 18 - [cancel] Without releasing their mouse press, the user moves their mouse outside the bounds of the link.
 19 Doing so cancels the long press, much like pressing a button on OS X and then moving outside
 20 that button's bounds cancels the button press.
 21 - The user releases their mouse press.
 22 - [trigger] Without releasing their mouse press, the user hovers over the original link again. Loop back
 23 to the grandparent's trigger event.
 24 - [cancel] The user releases their mouse press before triggering the long-press, triggering a normal mouse up.
 25 - [cancel] The user moves their mouse outside a small region around the original mouse press before triggering
 26 the long-press.
 27
 28 * page/EventHandler.h:
 29 Add four members to EventHandler:
 30 m_linkLongPressTimer -- timer tracking the delay between mousing down on a link and triggering a long-press.
 31 m_linkLongPressSource -- the link element. Stores the source link element of the long-press as soon as the
 32 mouse is pressed.
 33 m_didLongPressLink -- track whether a long-press was triggered at any point.
 34 m_linkLongPressMouseOutside -- track whether the mouse has moved outside the long-pressed link. Used to
 35 implement OS X-style button hovering behavior, i.e. long-pressing a link and
 36 then dragging the mouse outside the link will cancel the long-press.
 37
 38 * page/EventHandler.cpp:
 39 (WebCore::EventHandler::EventHandler):
 40 (WebCore::EventHandler::clear): Insert clearLinkLongPressState();
 41 (WebCore::EventHandler::handleMousePressEvent): Start the long-press if the mouse press is over a link.
 42 (WebCore::EventHandler::handleMouseReleaseEvent): Cancel the long-press when the mouse goes up.
 43 (WebCore::EventHandler::startLinkLongPressWithSource):
 44 Added. Starts the long-press timer and stores the source of the long-press.
 45 (WebCore::EventHandler::triggerLinkLongPress): Added. Will send up the long-press event.
 46 (WebCore::EventHandler::cancelLinkLongPress): Added. Will send up the link long-press event.
 47 (WebCore::EventHandler::cancelLinkLongPressTimer):
 48 Added. Cancel the long-press timer. Distinct from cancelLinkLongPress() because cancelLinkLongPress() will
 49 send up a cancel event in a future patch.
 50 (WebCore::EventHandler::clearLinkLongPressState): Added. Clear member variables.
 51 (WebCore::EventHandler::linkLongPressTimerFired):
 52 Added. Trigger the long-press and disable other actions like dragging.
 53 (WebCore::EventHandler::handleLinkLongPressMouseMovedEvent):
 54 Added. Cancels the long-press if the mouse moves outside a specified hysteresis before triggering. Cancel the
 55 link long-press if triggered but the mouse moves outside the original URL element.
 56 (WebCore::EventHandler::handleMouseMoveEvent): Call handleLinkLongPressEvent to handle the move.
 57 (WebCore::EventHandler::handleDrag): Long-press and drag are mutually exclusive, so cancel long-press.
 58 (WebCore::EventHandler::mouseHysteresisExceeded): Added. General hysteresis function that takes an arbitrary
 59 mouse movement threshold. Factored out from dragHysteresisExceeded.
 60 (WebCore::EventHandler::dragHysteresisExceeded): Factored out the hysteresis bounds check into
 61 mouseHysteresisExceeded().
 62
1632014-06-30 Alex Christensen <achristensen@webkit.org>
264
365 Use non-thumb registers in armv7 css jit.

Source/WebCore/page/EventHandler.cpp

@@const double cursorUpdateInterval = 0.02;
161161
162162const int maximumCursorSize = 128;
163163#endif
 164
 165#if ENABLE(LINK_LONG_PRESS)
 166const double linkLongPressDelay = 0.5;
 167const int linkLongPressHysteresis = 5;
 168#endif
164169
165170#if ENABLE(MOUSE_CURSOR_SCALE)
166171// It's pretty unlikely that a scale of less than one would ever be used. But all we really

@@EventHandler::EventHandler(Frame& frame)
336341#if ENABLE(CURSOR_SUPPORT)
337342 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
338343#endif
 344#if ENABLE(LINK_LONG_PRESS)
 345 , m_linkLongPressTimer(this, &EventHandler::linkLongPressTimerFired)
 346 , m_linkLongPressSource(nullptr)
 347 , m_didLongPressLink(false)
 348 , m_linkLongPressMouseOutside(false)
 349#endif
339350 , m_autoscrollController(std::make_unique<AutoscrollController>())
340351 , m_mouseDownMayStartAutoscroll(false)
341352 , m_mouseDownWasInSubframe(false)

@@void EventHandler::clear()
412423#if ENABLE(CURSOR_VISIBILITY)
413424 cancelAutoHideCursorTimer();
414425#endif
 426#if ENABLE(LINK_LONG_PRESS)
 427 clearLinkLongPressState();
 428#endif
 429
415430 m_resizeLayer = 0;
416431 m_elementUnderMouse = nullptr;
417432 m_lastElementUnderMouse = nullptr;

@@bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve
710725 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
711726 m_mouseDownMayStartDrag = singleClick;
712727#endif
 728
 729#if ENABLE(LINK_LONG_PRESS)
 730 if (event.isOverLink() && event.event().button() == LeftButton)
 731 startLinkLongPressWithSource(event.hitTestResult().URLElement());
 732#endif
713733
714734 m_mouseDownWasSingleClickInSelection = false;
715735

@@bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e
967987 m_mouseDownWasInSubframe = false;
968988
969989 bool handled = false;
 990
 991#if ENABLE(LINK_LONG_PRESS)
 992 if (event.event().button() == LeftButton) {
 993 cancelLinkLongPress();
 994 clearLinkLongPressState();
 995 }
 996#endif
970997
971998 // Clear the selection if the mouse didn't move after the last mouse
972999 // press and it's not a context menu click. We do this so when clicking

@@void EventHandler::autoHideCursorTimerFired(Timer<EventHandler>& timer)
15101537 view->setCursor(m_currentMouseCursor);
15111538}
15121539#endif
 1540
 1541#if ENABLE(LINK_LONG_PRESS)
 1542void EventHandler::startLinkLongPressWithSource(Element* element)
 1543{
 1544 clearLinkLongPressState();
 1545
 1546 m_linkLongPressSource = element;
 1547 m_linkLongPressTimer.startOneShot(linkLongPressDelay);
 1548
 1549 // FIXME: send link information up to UI process.
 1550}
 1551
 1552void EventHandler::triggerLinkLongPress()
 1553{
 1554 // FIXME: send link information up to UI process.
 1555}
 1556
 1557void EventHandler::cancelLinkLongPress()
 1558{
 1559 if (!m_linkLongPressSource.get())
 1560 return;
 1561
 1562 // Moving the mouse outside of the source element will cancel the long-press, so we return early if that's already happened.
 1563 if (m_linkLongPressMouseOutside)
 1564 return;
 1565
 1566 cancelLinkLongPressTimer();
 1567
 1568 // FIXME: send link information up to UI process.
 1569}
 1570
 1571void EventHandler::cancelLinkLongPressTimer()
 1572{
 1573 if (m_linkLongPressTimer.isActive())
 1574 m_linkLongPressTimer.stop();
 1575}
 1576
 1577void EventHandler::clearLinkLongPressState()
 1578{
 1579 cancelLinkLongPressTimer();
 1580 m_linkLongPressSource = nullptr;
 1581 m_didLongPressLink = false;
 1582 m_linkLongPressMouseOutside = false;
 1583}
 1584
 1585void EventHandler::linkLongPressTimerFired(Timer<EventHandler>& timer)
 1586{
 1587 ASSERT_UNUSED(timer, &timer == &m_linkLongPressTimer);
 1588
 1589 m_didLongPressLink = true;
 1590
 1591 // Clear mouse state to avoid initiating a drag.
 1592 m_mousePressed = false;
 1593 invalidateClick();
 1594
 1595 triggerLinkLongPress();
 1596}
 1597
 1598void EventHandler::handleLinkLongPressMouseMovedEvent(const WebCore::MouseEventWithHitTestResults &mev)
 1599{
 1600 bool exceededHysteresis = mouseHysteresisExceeded(mev.event().position(), linkLongPressHysteresis);
 1601 if (!m_didLongPressLink) {
 1602 if (exceededHysteresis) {
 1603 cancelLinkLongPress();
 1604 clearLinkLongPressState();
 1605 }
 1606 return;
 1607 }
 1608
 1609 bool mouseInside = m_linkLongPressSource.get() == mev.hitTestResult().URLElement() || !exceededHysteresis;
 1610
 1611 if (!mouseInside && !m_linkLongPressMouseOutside) {
 1612 cancelLinkLongPress();
 1613 m_linkLongPressMouseOutside = true;
 1614 } else if (mouseInside && m_linkLongPressMouseOutside) {
 1615 triggerLinkLongPress();
 1616 m_linkLongPressMouseOutside = false;
 1617 }
 1618}
 1619
 1620#endif // ENABLE(LINK_LONG_PRESS)
15131621
15141622static LayoutPoint documentPointForWindowPoint(Frame& frame, const IntPoint& windowPoint)
15151623{

@@bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
18601968 return true;
18611969
18621970 swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
 1971#if ENABLE(LINK_LONG_PRESS)
 1972 if (!swallowEvent && mev.event().button() == LeftButton)
 1973 handleLinkLongPressMouseMovedEvent(mev);
 1974#endif
 1975
18631976#if ENABLE(DRAG_SUPPORT)
18641977 if (!swallowEvent)
18651978 swallowEvent = handleMouseDraggedEvent(mev);

@@bool EventHandler::dragHysteresisExceeded(const IntPoint& floatDragViewportLocat
31783291
31793292bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation) const
31803293{
3181  FrameView* view = m_frame.view();
3182  if (!view)
3183  return false;
3184  IntPoint dragLocation = view->windowToContents(flooredIntPoint(dragViewportLocation));
3185  IntSize delta = dragLocation - m_mouseDownPos;
3186 
31873294 int threshold = GeneralDragHysteresis;
31883295 switch (dragState().type) {
31893296 case DragSourceActionSelection:

@@bool EventHandler::dragHysteresisExceeded(const FloatPoint& dragViewportLocation
32023309 ASSERT_NOT_REACHED();
32033310 }
32043311
3205  return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
 3312 return mouseHysteresisExceeded(dragViewportLocation, threshold);
32063313}
32073314
32083315void EventHandler::freeDataTransfer()

@@bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr
33753482 // In WebKit2 we could re-enter this code and start another drag.
33763483 // On OS X this causes problems with the ownership of the pasteboard and the promised types.
33773484 if (m_didStartDrag) {
 3485#if ENABLE(LINK_LONG_PRESS)
 3486 cancelLinkLongPress();
 3487 clearLinkLongPressState();
 3488#endif
33783489 m_mouseDownMayStartDrag = false;
33793490 return true;
33803491 }

@@cleanupDrag:
33963507 return true;
33973508}
33983509#endif // ENABLE(DRAG_SUPPORT)
 3510
 3511#if ENABLE(DRAG_SUPPORT) || ENABLE(LINK_LONG_PRESS)
 3512bool EventHandler::mouseHysteresisExceeded(const FloatPoint& viewportLocation, const int threshold) const
 3513{
 3514 FrameView* view = m_frame.view();
 3515 if (!view)
 3516 return false;
 3517 IntPoint location = view->windowToContents(flooredIntPoint(viewportLocation));
 3518 IntSize delta = location - m_mouseDownPos;
 3519
 3520 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
 3521}
 3522#endif // ENABLE(DRAG_SUPPORT) || ENABLE(LINK_LONG_PRESS)
33993523
34003524bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
34013525{

Source/WebCore/page/EventHandler.h

@@private:
378378 bool dragHysteresisExceeded(const FloatPoint&) const;
379379 bool dragHysteresisExceeded(const IntPoint&) const;
380380#endif // ENABLE(DRAG_SUPPORT)
 381
 382#if ENABLE(DRAG_SUPPORT) || ENABLE(LINK_LONG_PRESS)
 383 bool mouseHysteresisExceeded(const FloatPoint&, const int) const;
 384#endif
381385
382386 bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
383387 bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);

@@private:
437441 void autoHideCursorTimerFired(Timer<EventHandler>&);
438442#endif
439443
 444#if ENABLE(LINK_LONG_PRESS)
 445 void startLinkLongPressWithSource(Element*);
 446 void triggerLinkLongPress();
 447 void cancelLinkLongPress();
 448 bool linkLongPressHysteresisExceeded();
 449 void clearLinkLongPressState();
 450 void linkLongPressTimerFired(Timer<EventHandler>&);
 451 void cancelLinkLongPressTimer();
 452 void handleLinkLongPressMouseMovedEvent(const MouseEventWithHitTestResults&);
 453#endif
 454
440455 void clearLatchedState();
441456
442457 Frame& m_frame;

@@private:
464479#if ENABLE(CURSOR_SUPPORT)
465480 Timer<EventHandler> m_cursorUpdateTimer;
466481#endif
 482#if ENABLE(LINK_LONG_PRESS)
 483 Timer<EventHandler> m_linkLongPressTimer;
 484 RefPtr<Element> m_linkLongPressSource;
 485 bool m_didLongPressLink;
 486 bool m_linkLongPressMouseOutside;
 487#endif
467488
468489 std::unique_ptr<AutoscrollController> m_autoscrollController;
469490 bool m_mouseDownMayStartAutoscroll;