Index: Source/WebCore/page/EventHandler.cpp |
=================================================================== |
--- Source/WebCore/page/EventHandler.cpp (revision 145820) |
+++ Source/WebCore/page/EventHandler.cpp (working copy) |
@@ -403,6 +403,7 @@ |
#if ENABLE(GESTURE_EVENTS) |
m_scrollGestureHandlingNode = 0; |
m_lastHitTestResultOverWidget = false; |
+ m_previousGestureScrolledNode = 0; |
m_scrollbarHandlingScrollGesture = 0; |
#endif |
m_maxMouseMovedDuration = 0; |
@@ -2498,6 +2499,9 @@ |
case PlatformEvent::GestureScrollUpdate: |
case PlatformEvent::GestureScrollUpdateWithoutPropagation: |
return handleGestureScrollUpdate(gestureEvent); |
+ case PlatformEvent::GestureScrollEnd: |
+ clearGestureScrollNodes(); |
+ return true; |
case PlatformEvent::GestureTap: |
return handleGestureTap(gestureEvent); |
case PlatformEvent::GestureTapDown: |
@@ -2508,7 +2512,6 @@ |
return handleGestureLongTap(gestureEvent); |
case PlatformEvent::GestureTwoFingerTap: |
return handleGestureTwoFingerTap(gestureEvent); |
- case PlatformEvent::GestureScrollEnd: |
case PlatformEvent::GestureDoubleTap: |
case PlatformEvent::GesturePinchBegin: |
case PlatformEvent::GesturePinchEnd: |
@@ -2636,18 +2639,6 @@ |
return false; |
} |
-static const Node* closestScrollableNodeCandidate(const Node* node) |
-{ |
- for (const Node* scrollableNode = node; scrollableNode; scrollableNode = scrollableNode->parentNode()) { |
- if (scrollableNode->isDocumentNode()) |
- return scrollableNode; |
- RenderObject* renderer = scrollableNode->renderer(); |
- if (renderer && renderer->isBox() && toRenderBox(renderer)->canBeScrolledAndHasScrollableArea()) |
- return scrollableNode; |
- } |
- return node; |
-} |
- |
bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent) |
{ |
Document* document = m_frame->document(); |
@@ -2666,6 +2657,7 @@ |
m_lastHitTestResultOverWidget = result.isOverWidget(); |
m_scrollGestureHandlingNode = result.innerNode(); |
+ m_previousGestureScrolledNode = 0; |
Node* node = m_scrollGestureHandlingNode.get(); |
if (node) |
@@ -2676,50 +2668,81 @@ |
bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent) |
{ |
- // Ignore this event if we don't already have a targeted node with a valid renderer. |
- const Node* node = m_scrollGestureHandlingNode.get(); |
- if (!node) |
+ FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY()); |
+ if (delta.isZero()) |
return false; |
- RenderObject* latchedRenderer = node->renderer(); |
- if (!latchedRenderer) |
- return false; |
+ const float scaleFactor = m_frame->pageZoomFactor() * m_frame->frameScaleFactor(); |
+ delta.scale(1 / scaleFactor, 1 / scaleFactor); |
- IntSize delta(-gestureEvent.deltaX(), -gestureEvent.deltaY()); |
- if (delta.isZero()) |
+ Node* node = m_scrollGestureHandlingNode.get(); |
+ if (!node) |
+ return sendScrollEventToView(gestureEvent, delta); |
+ |
+ // Ignore this event if the targeted node does not have a valid renderer. |
+ RenderObject* renderer = node->renderer(); |
+ if (!renderer) |
return false; |
RefPtr<FrameView> protector(m_frame->view()); |
// Try to send the event to the correct view. |
- if (passGestureEventToWidgetIfPossible(gestureEvent, latchedRenderer)) |
+ if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) |
return true; |
- // Otherwise if this is the correct view for the event, find the closest scrollable |
- // ancestor of the targeted node and scroll the layer that contains this node's renderer. |
- node = closestScrollableNodeCandidate(node); |
- if (!node) |
- return false; |
+ Node* stopNode = 0; |
+ bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation; |
+ if (scrollShouldNotPropagate) |
+ stopNode = m_previousGestureScrolledNode.get(); |
- latchedRenderer = node->renderer(); |
- if (!latchedRenderer) |
- return false; |
+ // First try to scroll the closest scrollable RenderBox ancestor of |node|. |
+ ScrollGranularity granularity = ScrollByPixel; |
+ bool horizontalScroll = scrollNode(delta.width(), granularity, ScrollLeft, ScrollRight, node, &stopNode); |
+ bool verticalScroll = scrollNode(delta.height(), granularity, ScrollUp, ScrollDown, node, &stopNode); |
- RenderLayer::ScrollPropagation shouldPropagate = RenderLayer::ShouldPropagateScroll; |
- if (gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) |
- shouldPropagate = RenderLayer::DontPropagateScroll; |
+ if (scrollShouldNotPropagate) |
+ m_previousGestureScrolledNode = stopNode; |
- const float scaleFactor = m_frame->pageZoomFactor() * m_frame->frameScaleFactor(); |
- delta.scale(1 / scaleFactor, 1 / scaleFactor); |
+ if (horizontalScroll || verticalScroll) { |
+ setFrameWasScrolledByUser(); |
+ return true; |
+ } |
- bool result = latchedRenderer->enclosingLayer()->scrollBy(delta, RenderLayer::ScrollOffsetClamped, shouldPropagate); |
+ // Otherwise try to scroll the view. |
+ return sendScrollEventToView(gestureEvent, delta); |
+} |
- if (result) |
+bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta) |
+{ |
+ FrameView* view = m_frame->view(); |
+ if (!view) |
+ return false; |
+ |
+ const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier); |
+ IntPoint point(gestureEvent.position().x(), gestureEvent.position().y()); |
+ IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y()); |
+ PlatformWheelEvent syntheticWheelEvent(point, globalPoint, |
+ scaledDelta.width(), scaledDelta.height(), |
+ scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor, |
+ ScrollByPixelWheelEvent, |
+ gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey()); |
+#if PLATFORM(MAC) || PLATFORM(CHROMIUM) |
+ syntheticWheelEvent.setHasPreciseScrollingDeltas(true); |
+#endif |
+ |
+ bool scrolledFrame = view->wheelEvent(syntheticWheelEvent); |
+ if (scrolledFrame) |
setFrameWasScrolledByUser(); |
- return result; |
+ return scrolledFrame; |
} |
+void EventHandler::clearGestureScrollNodes() |
+{ |
+ m_scrollGestureHandlingNode = 0; |
+ m_previousGestureScrolledNode = 0; |
+} |
+ |
bool EventHandler::isScrollbarHandlingGestures() const |
{ |
return m_scrollbarHandlingScrollGesture.get(); |