diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-03-12 14:11:15 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-03-12 14:11:15 +0100 |
commit | dd91e772430dc294e3bf478c119ef8d43c0a3358 (patch) | |
tree | 6f33ce4d5872a5691e0291eb45bf6ab373a5f567 /Source/WebCore/page/EventHandler.cpp | |
parent | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (diff) | |
download | qtwebkit-dd91e772430dc294e3bf478c119ef8d43c0a3358.tar.gz |
Imported WebKit commit 3db4eb1820ac8fb03065d7ea73a4d9db1e8fea1a (http://svn.webkit.org/repository/webkit/trunk@110422)
This includes build fixes for the latest qtbase/qtdeclarative as well as the final QML2 API.
Diffstat (limited to 'Source/WebCore/page/EventHandler.cpp')
-rw-r--r-- | Source/WebCore/page/EventHandler.cpp | 165 |
1 files changed, 112 insertions, 53 deletions
diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index 4f0ddeee3..1738db896 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -83,6 +83,7 @@ #include <wtf/Assertions.h> #include <wtf/CurrentTime.h> #include <wtf/StdLibExtras.h> +#include <wtf/TemporaryChange.h> #if ENABLE(GESTURE_EVENTS) #include "PlatformGestureEvent.h" @@ -126,7 +127,11 @@ using namespace SVGNames; // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth const double autoscrollInterval = 0.05; -const double fakeMouseMoveInterval = 0.1; +// The amount of time to wait before sending a fake mouse event, triggered +// during a scroll. The short interval is used if the content responds to the mouse events quickly enough, +// otherwise the long interval is used. +const double fakeMouseMoveShortInterval = 0.1; +const double fakeMouseMoveLongInterval = 0.250; enum NoCursorChangeType { NoCursorChange }; @@ -143,6 +148,24 @@ private: Cursor m_cursor; }; +class MaximumDurationTracker { +public: + explicit MaximumDurationTracker(double *maxDuration) + : m_maxDuration(maxDuration) + , m_start(monotonicallyIncreasingTime()) + { + } + + ~MaximumDurationTracker() + { + *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start); + } + +private: + double* m_maxDuration; + double m_start; +}; + #if ENABLE(TOUCH_EVENTS) class SyntheticTouchPoint : public PlatformTouchPoint { public: @@ -210,29 +233,28 @@ public: }; #endif -static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode) +static inline ScrollGranularity wheelGranularityToScrollGranularity(WheelEvent::Granularity granularity) +{ + switch (granularity) { + case WheelEvent::Page: + return ScrollByPage; + case WheelEvent::Line: + return ScrollByLine; + case WheelEvent::Pixel: + return ScrollByPixel; + } + return ScrollByPixel; +} + +static inline bool scrollNode(float delta, ScrollGranularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode) { if (!delta) return false; - if (!node->renderer()) return false; - - // Find the nearest enclosing box. RenderBox* enclosingBox = node->renderer()->enclosingBox(); - float absDelta = delta > 0 ? delta : -delta; - - if (granularity == WheelEvent::Page) - return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode); - - if (granularity == WheelEvent::Line) - return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode); - - if (granularity == WheelEvent::Pixel) - return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode); - - return false; + return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, granularity, absDelta, stopNode); } #if !PLATFORM(MAC) @@ -289,6 +311,8 @@ EventHandler::EventHandler(Frame* frame) #if ENABLE(TOUCH_EVENTS) , m_touchPressed(false) #endif + , m_maxMouseMovedDuration(0) + , m_baseEventType(PlatformEvent::NoType) { } @@ -335,6 +359,10 @@ void EventHandler::clear() #if ENABLE(TOUCH_EVENTS) m_originatingTouchPointTargets.clear(); #endif + m_maxMouseMovedDuration = 0; +#if ENABLE(GESTURE_EVENTS) + m_baseEventType = PlatformEvent::NoType; +#endif } void EventHandler::nodeWillBeRemoved(Node* nodeToBeRemoved) @@ -1261,8 +1289,8 @@ OptionalCursor EventHandler::selectCursor(const MouseEventWithHitTestResults& ev const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor(); // During selection, use an I-beam no matter what we're over. - // If you're capturing mouse events for a particular node, don't treat this as a selection. - if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode) + // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection. + if (m_mousePressed && m_mouseDownMayStartSelect && !m_mouseDownMayStartDrag && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode) return iBeam; if (renderer) { @@ -1635,8 +1663,10 @@ static RenderLayer* layerForNode(Node* node) bool EventHandler::mouseMoved(const PlatformMouseEvent& event) { + MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration); RefPtr<FrameView> protector(m_frame->view()); + #if ENABLE(TOUCH_EVENTS) // FIXME: this should be moved elsewhere to also be able to dispatch touchcancel events. bool defaultPrevented = dispatchSyntheticTouchEventIfEnabled(event); @@ -2287,7 +2317,7 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) // Instead, the handlers should know convert vertical scrolls // appropriately. PlatformWheelEvent event = e; - if (shouldTurnVerticalTicksIntoHorizontal(result)) + if (m_baseEventType != PlatformEvent::NoType && shouldTurnVerticalTicksIntoHorizontal(result)) event = event.copyTurningVerticalTicksIntoHorizontalTicks(); if (node) { @@ -2313,20 +2343,21 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e) return view->wheelEvent(event); } - + void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent) { if (!startNode || !wheelEvent) return; Node* stopNode = m_previousWheelScrolledNode.get(); + ScrollGranularity granularity = m_baseEventType == PlatformEvent::GestureScrollEnd ? ScrollByPixelVelocity : wheelGranularityToScrollGranularity(wheelEvent->granularity()); // Break up into two scrolls if we need to. Diagonal movement on // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set). - if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode)) + if (scrollNode(wheelEvent->rawDeltaX(), granularity, ScrollLeft, ScrollRight, startNode, &stopNode)) wheelEvent->setDefaultHandled(); - if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode)) + if (scrollNode(wheelEvent->rawDeltaY(), granularity, ScrollUp, ScrollDown, startNode, &stopNode)) wheelEvent->setDefaultHandled(); if (!m_useLatchedWheelEventNode) @@ -2336,41 +2367,60 @@ void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEv #if ENABLE(GESTURE_EVENTS) bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent) { - // FIXME: This should hit test and go to the correct subframe rather than - // always sending gestures to the main frame only. We should also ensure - // that if a frame gets a gesture begin gesture, it gets the corresponding - // end gesture as well. + // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will + // eliminate the need for this. + TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type()); switch (gestureEvent.type()) { case PlatformEvent::GestureTapDown: + // FIXME: Stop animation here. break; - case PlatformEvent::GestureTap: { - // FIXME: Refactor this code to not hit test multiple times once hit testing has been corrected as suggested above. - PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); - PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); - PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); - mouseMoved(fakeMouseMove); - handleMousePressEvent(fakeMouseDown); - handleMouseReleaseEvent(fakeMouseUp); - return true; - } - case PlatformEvent::GestureScrollUpdate: { - const float tickDivisor = (float)WheelEvent::tickMultiplier; - // FIXME: Replace this interim implementation once the above fixme has been addressed. - IntPoint point(gestureEvent.position().x(), gestureEvent.position().y()); - IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y()); - PlatformWheelEvent syntheticWheelEvent(point, globalPoint, gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor, ScrollByPixelWheelEvent, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey()); - handleWheelEvent(syntheticWheelEvent); - return true; - } + case PlatformEvent::GestureTap: + return handleGestureTap(gestureEvent); + case PlatformEvent::GestureScrollUpdate: + return handleGestureScrollUpdate(gestureEvent); case PlatformEvent::GestureDoubleTap: + break; case PlatformEvent::GestureScrollBegin: + return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, false); case PlatformEvent::GestureScrollEnd: - break; + return handleGestureScrollCore(gestureEvent, ScrollByPixelVelocityWheelEvent, true); default: ASSERT_NOT_REACHED(); } - return true; + + return false; +} + +bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent) +{ + // FIXME: Refactor this code to not hit test multiple times. + bool defaultPrevented = false; + PlatformMouseEvent fakeMouseMove(gestureEvent.position(), gestureEvent.globalPosition(), NoButton, PlatformEvent::MouseMoved, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); + PlatformMouseEvent fakeMouseDown(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); + PlatformMouseEvent fakeMouseUp(gestureEvent.position(), gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseReleased, /* clickCount */ 1, gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp()); + mouseMoved(fakeMouseMove); + defaultPrevented |= handleMousePressEvent(fakeMouseDown); + defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp); + return defaultPrevented; +} + +bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) +{ + return handleGestureScrollCore(gestureEvent, ScrollByPixelWheelEvent, true); +} + +bool EventHandler::handleGestureScrollCore(const PlatformGestureEvent& gestureEvent, PlatformWheelEventGranularity granularity, bool latchedWheel) +{ + TemporaryChange<bool> latched(m_useLatchedWheelEventNode, latchedWheel); + const float tickDivisor = (float)WheelEvent::tickMultiplier; + IntPoint point(gestureEvent.position().x(), gestureEvent.position().y()); + IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y()); + PlatformWheelEvent syntheticWheelEvent(point, globalPoint, + gestureEvent.deltaX(), gestureEvent.deltaY(), gestureEvent.deltaX() / tickDivisor, gestureEvent.deltaY() / tickDivisor, + granularity, + gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey()); + return handleWheelEvent(syntheticWheelEvent); } #endif @@ -2488,8 +2538,18 @@ void EventHandler::dispatchFakeMouseMoveEventSoon() if (m_mousePressed) return; - if (!m_fakeMouseMoveEventTimer.isActive()) - m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval); + // If the content has ever taken longer than fakeMouseMoveShortInterval we + // reschedule the timer and use a longer time. This will cause the content + // to receive these moves only after the user is done scrolling, reducing + // pauses during the scroll. + if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) { + if (m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.stop(); + m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval); + } else { + if (!m_fakeMouseMoveEventTimer.isActive()) + m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval); + } } void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) @@ -2498,11 +2558,10 @@ void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad) if (!view) return; - if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition))) + if (!quad.containsPoint(view->windowToContents(m_currentMousePosition))) return; - if (!m_fakeMouseMoveEventTimer.isActive()) - m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval); + dispatchFakeMouseMoveEventSoon(); } void EventHandler::cancelFakeMouseMoveEvent() |