summaryrefslogtreecommitdiff
path: root/Source/WebCore/page/EventHandler.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-03-12 14:11:15 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-03-12 14:11:15 +0100
commitdd91e772430dc294e3bf478c119ef8d43c0a3358 (patch)
tree6f33ce4d5872a5691e0291eb45bf6ab373a5f567 /Source/WebCore/page/EventHandler.cpp
parentad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (diff)
downloadqtwebkit-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.cpp165
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()