summaryrefslogtreecommitdiffstats
path: root/WebCore/page/EventHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/page/EventHandler.cpp')
-rw-r--r--WebCore/page/EventHandler.cpp788
1 files changed, 629 insertions, 159 deletions
diff --git a/WebCore/page/EventHandler.cpp b/WebCore/page/EventHandler.cpp
index 4ecbe13..3f45b92 100644
--- a/WebCore/page/EventHandler.cpp
+++ b/WebCore/page/EventHandler.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "EventHandler.h"
+#include "AXObjectCache.h"
#include "CachedImage.h"
#include "ChromeClient.h"
#include "Cursor.h"
@@ -35,6 +36,7 @@
#include "Editor.h"
#include "EventNames.h"
#include "FloatPoint.h"
+#include "FloatRect.h"
#include "FocusController.h"
#include "Frame.h"
#include "FrameLoader.h"
@@ -47,28 +49,35 @@
#include "HTMLInputElement.h"
#include "HTMLNames.h"
#include "Image.h"
+#include "InspectorController.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "MouseEventWithHitTestResults.h"
#include "Page.h"
#include "PlatformKeyboardEvent.h"
-#include "PlatformScrollBar.h"
#include "PlatformWheelEvent.h"
+#include "RenderFrameSet.h"
#include "RenderWidget.h"
+#include "RenderView.h"
+#include "Scrollbar.h"
#include "SelectionController.h"
#include "Settings.h"
#include "TextEvent.h"
#if ENABLE(SVG)
-#include "SVGCursorElement.h"
#include "SVGDocument.h"
-#include "SVGLength.h"
+#include "SVGElementInstance.h"
#include "SVGNames.h"
+#include "SVGUseElement.h"
+#endif
+
+#if ENABLE(TOUCH_EVENTS) // Android
+#include "TouchEvent.h"
+#include "PlatformTouchEvent.h"
#endif
namespace WebCore {
-using namespace EventNames;
using namespace HTMLNames;
// The link drag hysteresis is much larger than the others because there
@@ -78,7 +87,6 @@ const int LinkDragHysteresis = 40;
const int ImageDragHysteresis = 5;
const int TextDragHysteresis = 3;
const int GeneralDragHysteresis = 3;
-const double TextDragDelay = 0.15;
// Match key code of composition keydown event on windows.
// IE sends VK_PROCESSKEY which has value 229;
@@ -88,9 +96,27 @@ const int CompositionEventKeyCode = 229;
using namespace SVGNames;
#endif
-const double autoscrollInterval = 0.1;
+// When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
+const double autoscrollInterval = 0.05;
-static Frame* subframeForTargetNode(Node* node);
+static Frame* subframeForTargetNode(Node*);
+static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
+
+static inline void scrollAndAcceptEvent(float delta, ScrollDirection positiveDirection, ScrollDirection negativeDirection, PlatformWheelEvent& e, Node* node)
+{
+ if (!delta)
+ return;
+ if (e.granularity() == ScrollByPageWheelEvent) {
+ if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, 1))
+ e.accept();
+ return;
+ }
+ float pixelsToScroll = delta > 0 ? delta : -delta;
+ if (e.granularity() == ScrollByLineWheelEvent)
+ pixelsToScroll *= cMouseWheelPixelsPerLineStep;
+ if (node->renderer()->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, pixelsToScroll))
+ e.accept();
+}
EventHandler::EventHandler(Frame* frame)
: m_frame(frame)
@@ -99,9 +125,11 @@ EventHandler::EventHandler(Frame* frame)
, m_mouseDownMayStartDrag(false)
, m_mouseDownWasSingleClickInSelection(false)
, m_beganSelectingText(false)
+ , m_panScrollInProgress(false)
, m_hoverTimer(this, &EventHandler::hoverTimerFired)
, m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
, m_autoscrollRenderer(0)
+ , m_autoscrollInProgress(false)
, m_mouseDownMayStartAutoscroll(false)
, m_mouseDownWasInSubframe(false)
#if ENABLE(SVG)
@@ -111,6 +139,8 @@ EventHandler::EventHandler(Frame* frame)
, m_capturingMouseEventsNode(0)
, m_clickCount(0)
, m_mouseDownTimestamp(0)
+ , m_pendingFrameUnloadEventCount(0)
+ , m_pendingFrameBeforeUnloadEventCount(0)
#if PLATFORM(MAC)
, m_mouseDownView(nil)
, m_sendingEventToSubview(false)
@@ -135,10 +165,17 @@ void EventHandler::clear()
m_resizeLayer = 0;
m_nodeUnderMouse = 0;
m_lastNodeUnderMouse = 0;
+#if ENABLE(SVG)
+ m_instanceUnderMouse = 0;
+ m_lastInstanceUnderMouse = 0;
+#endif
m_lastMouseMoveEventSubframe = 0;
m_lastScrollbarUnderMouse = 0;
m_clickCount = 0;
m_clickNode = 0;
+#if ENABLE(TOUCH_EVENTS) // Android
+ m_touch = 0;
+#endif
m_frameSetBeingResized = 0;
m_dragTarget = 0;
m_currentMousePosition = IntPoint();
@@ -165,7 +202,7 @@ void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestRe
}
if (m_frame->shouldChangeSelection(newSelection))
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setSelection(newSelection);
}
}
@@ -189,7 +226,7 @@ void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHit
}
if (m_frame->shouldChangeSelection(newSelection))
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setSelection(newSelection);
}
}
@@ -198,7 +235,7 @@ bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestR
if (event.event().button() != LeftButton)
return false;
- if (m_frame->selectionController()->isRange())
+ if (m_frame->selection()->isRange())
// A double-click when range is already selected
// should not change the selection. So, do not call
// selectClosestWordFromMouseEvent, but do set
@@ -232,7 +269,7 @@ bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestR
}
if (m_frame->shouldChangeSelection(newSelection))
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setSelection(newSelection);
return true;
}
@@ -252,7 +289,7 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR
// Don't restart the selection when the mouse is pressed on an
// existing selection so we can allow for text dragging.
IntPoint vPoint = m_frame->view()->windowToContents(event.event().pos());
- if (!extendSelection && m_frame->selectionController()->contains(vPoint)) {
+ if (!extendSelection && m_frame->selection()->contains(vPoint)) {
m_mouseDownWasSingleClickInSelection = true;
return false;
}
@@ -262,9 +299,9 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR
visiblePos = VisiblePosition(innerNode, 0, DOWNSTREAM);
Position pos = visiblePos.deepEquivalent();
- Selection newSelection = m_frame->selectionController()->selection();
+ Selection newSelection = m_frame->selection()->selection();
if (extendSelection && newSelection.isCaretOrRange()) {
- m_frame->selectionController()->setLastChangeWasHorizontalExtension(false);
+ m_frame->selection()->setLastChangeWasHorizontalExtension(false);
// See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
// was created right-to-left
@@ -285,7 +322,7 @@ bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestR
}
if (m_frame->shouldChangeSelection(newSelection))
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setSelection(newSelection);
return true;
}
@@ -306,7 +343,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve
m_mouseDownWasSingleClickInSelection = false;
- if (passWidgetMouseDownEventToWidget(event))
+ if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
return true;
#if ENABLE(SVG)
@@ -332,7 +369,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve
bool swallowEvent = false;
if (event.event().button() == LeftButton || event.event().button() == MiddleButton) {
- m_frame->selectionController()->setCaretBlinkingSuspended(true);
+ m_frame->selection()->setCaretBlinkingSuspended(true);
m_mousePressed = true;
m_beganSelectingText = false;
@@ -345,7 +382,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve
}
m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect ||
- (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->renderer()->shouldAutoscroll());
+ (m_mousePressNode && m_mousePressNode->renderer() && m_mousePressNode->renderer()->canBeProgramaticallyScrolled(true));
return swallowEvent;
}
@@ -368,14 +405,23 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e
m_mouseDownMayStartDrag = false;
- if (m_mouseDownMayStartAutoscroll) {
+ if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
// If the selection is contained in a layer that can scroll, that layer should handle the autoscroll
// Otherwise, let the bridge handle it so the view can scroll itself.
RenderObject* renderer = targetNode->renderer();
- while (renderer && !renderer->shouldAutoscroll())
- renderer = renderer->parent();
- if (renderer)
+ while (renderer && !renderer->canBeProgramaticallyScrolled(false)) {
+ if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
+ renderer = renderer->document()->ownerElement()->renderer();
+ else
+ renderer = renderer->parent();
+ }
+
+ if (renderer) {
+ m_autoscrollInProgress = true;
handleAutoscroll(renderer);
+ }
+
+ m_mouseDownMayStartAutoscroll = false;
}
updateSelectionForMouseDrag(targetNode, event.localPoint());
@@ -388,7 +434,7 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
// that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
// in handleMousePressEvent
- if (!m_frame->renderer() || !m_frame->renderer()->hasLayer()
+ if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer()
|| event.button() != LeftButton || event.clickCount() != 1)
return false;
@@ -400,7 +446,7 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
HitTestRequest request(true, false);
HitTestResult result(m_frame->view()->windowToContents(event.pos()));
- m_frame->renderer()->layer()->hitTest(request, result);
+ m_frame->contentRenderer()->layer()->hitTest(request, result);
bool srcIsDHTML;
return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
}
@@ -410,7 +456,7 @@ void EventHandler::updateSelectionForMouseDrag()
FrameView* view = m_frame->view();
if (!view)
return;
- RenderObject* renderer = m_frame->renderer();
+ RenderObject* renderer = m_frame->contentRenderer();
if (!renderer)
return;
RenderLayer* layer = renderer->layer();
@@ -445,7 +491,7 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint&
// Restart the selection if this is the first mouse move. This work is usually
// done in handleMousePressEvent, but not if the mouse press was on an existing selection.
- Selection newSelection = m_frame->selectionController()->selection();
+ Selection newSelection = m_frame->selection()->selection();
#if ENABLE(SVG)
// Special case to limit selection to the containing block for SVG text.
@@ -467,8 +513,8 @@ void EventHandler::updateSelectionForMouseDrag(Node* targetNode, const IntPoint&
newSelection.expandUsingGranularity(m_frame->selectionGranularity());
if (m_frame->shouldChangeSelection(newSelection)) {
- m_frame->selectionController()->setLastChangeWasHorizontalExtension(false);
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setLastChangeWasHorizontalExtension(false);
+ m_frame->selection()->setSelection(newSelection);
}
}
@@ -487,14 +533,15 @@ bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
{
- stopAutoscrollTimer();
+ if (m_autoscrollInProgress)
+ stopAutoscrollTimer();
if (handleMouseUp(event))
return true;
// Used to prevent mouseMoveEvent from initiating a drag before
// the mouse is pressed again.
- m_frame->selectionController()->setCaretBlinkingSuspended(false);
+ m_frame->selection()->setCaretBlinkingSuspended(false);
m_mousePressed = false;
m_mouseDownMayStartDrag = false;
m_mouseDownMayStartSelect = false;
@@ -508,7 +555,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e
// However, if we are editing, place the caret.
if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
&& m_dragStartPos == event.event().pos()
- && m_frame->selectionController()->isRange()) {
+ && m_frame->selection()->isRange()) {
Selection newSelection;
Node *node = event.targetNode();
if (node && node->isContentEditable() && node->renderer()) {
@@ -516,34 +563,96 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e
newSelection = Selection(pos);
}
if (m_frame->shouldChangeSelection(newSelection))
- m_frame->selectionController()->setSelection(newSelection);
+ m_frame->selection()->setSelection(newSelection);
handled = true;
}
m_frame->notifyRendererOfSelectionChange(true);
- m_frame->selectionController()->selectFrameElementInParentIfFullySelected();
+ m_frame->selection()->selectFrameElementInParentIfFullySelected();
return handled;
}
void EventHandler::handleAutoscroll(RenderObject* renderer)
{
+ // We don't want to trigger the autoscroll or the panScroll if it's already active
if (m_autoscrollTimer.isActive())
- return;
+ return;
+
setAutoscrollRenderer(renderer);
+
+#if ENABLE(PAN_SCROLLING)
+ if (m_panScrollInProgress) {
+ m_panScrollStartPos = currentMousePosition();
+ m_frame->view()->addPanScrollIcon(m_panScrollStartPos);
+ // If we're not in the top frame we notify it that we are using the panScroll
+ if (m_frame != m_frame->page()->mainFrame())
+ m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(true);
+ }
+#endif
+
startAutoscrollTimer();
}
void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
{
- if (!m_mousePressed) {
+ RenderObject* r = autoscrollRenderer();
+ if (!r) {
stopAutoscrollTimer();
return;
}
- if (RenderObject* r = autoscrollRenderer())
+
+ if (m_autoscrollInProgress) {
+ if (!m_mousePressed) {
+ stopAutoscrollTimer();
+ return;
+ }
r->autoscroll();
+ } else {
+ // we verify that the main frame hasn't received the order to stop the panScroll
+ if (!m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress()) {
+ stopAutoscrollTimer();
+ return;
+ }
+#if ENABLE(PAN_SCROLLING)
+ setPanScrollCursor();
+ r->panScroll(m_panScrollStartPos);
+#endif
+ }
+}
+
+void EventHandler::setPanScrollCursor()
+{
+ // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
+ // So we don't want to change the cursor over this area
+ const int noScrollRadius = 9;
+ bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - noScrollRadius);
+ bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + noScrollRadius);
+ bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + noScrollRadius);
+ bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - noScrollRadius);
+
+ if (north) {
+ if (east)
+ m_frame->view()->setCursor(northEastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(northWestPanningCursor());
+ else
+ m_frame->view()->setCursor(northPanningCursor());
+ } else if (south) {
+ if (east)
+ m_frame->view()->setCursor(southEastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(southWestPanningCursor());
+ else
+ m_frame->view()->setCursor(southPanningCursor());
+ } else if (east)
+ m_frame->view()->setCursor(eastPanningCursor());
+ else if (west)
+ m_frame->view()->setCursor(westPanningCursor());
+ else
+ m_frame->view()->setCursor(middlePanningCursor());
}
RenderObject* EventHandler::autoscrollRenderer() const
@@ -551,6 +660,20 @@ RenderObject* EventHandler::autoscrollRenderer() const
return m_autoscrollRenderer;
}
+void EventHandler::updateAutoscrollRenderer()
+{
+ if (!m_autoscrollRenderer)
+ return;
+
+ HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
+
+ if (Node* nodeAtPoint = hitTest.innerNode())
+ m_autoscrollRenderer = nodeAtPoint->renderer();
+
+ while (m_autoscrollRenderer && !m_autoscrollRenderer->canBeProgramaticallyScrolled(false))
+ m_autoscrollRenderer = m_autoscrollRenderer->parent();
+}
+
void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
{
m_autoscrollRenderer = renderer;
@@ -561,6 +684,7 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
if (!m_frame || !m_frame->document()) {
flagDHTML = false;
flagUA = false;
+ return;
}
unsigned mask = m_frame->page()->dragController()->delegateDragSourceAction(m_frame->view()->contentsToWindow(m_mouseDownPos));
@@ -571,27 +695,37 @@ void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent)
{
HitTestResult result(point);
- if (!m_frame->renderer())
+ if (!m_frame->contentRenderer())
return result;
- m_frame->renderer()->layer()->hitTest(HitTestRequest(true, true), result);
+ m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), result);
while (true) {
Node* n = result.innerNode();
- if (!n || !n->renderer() || !n->renderer()->isWidget())
+ if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
break;
Widget* widget = static_cast<RenderWidget*>(n->renderer())->widget();
if (!widget || !widget->isFrameView())
break;
Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
- if (!frame || !frame->renderer())
+ if (!frame || !frame->contentRenderer())
break;
FrameView* view = static_cast<FrameView*>(widget);
- IntPoint widgetPoint(result.localPoint().x() + view->contentsX() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(),
- result.localPoint().y() + view->contentsY() - n->renderer()->borderTop() - n->renderer()->paddingTop());
+ IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - n->renderer()->borderLeft() - n->renderer()->paddingLeft(),
+ result.localPoint().y() + view->scrollY() - n->renderer()->borderTop() - n->renderer()->paddingTop());
HitTestResult widgetHitTestResult(widgetPoint);
- frame->renderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult);
+ frame->contentRenderer()->layer()->hitTest(HitTestRequest(true, true), widgetHitTestResult);
result = widgetHitTestResult;
}
+
+ // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
+ // Another hit test at the main frame level should get us the correct visible result.
+ Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
+ Frame* mainFrame = m_frame->page()->mainFrame();
+ if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
+ IntPoint windowPoint = resultFrame->view()->contentsToWindow(result.point());
+ IntPoint mainFramePoint = mainFrame->view()->windowToContents(windowPoint);
+ result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent);
+ }
if (!allowShadowContent)
result.setToNonShadowAncestor();
@@ -607,16 +741,34 @@ void EventHandler::startAutoscrollTimer()
void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
{
- if (m_mouseDownWasInSubframe) {
- if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
- subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
- return;
+ if (m_autoscrollInProgress) {
+ if (m_mouseDownWasInSubframe) {
+ if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
+ subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
+ return;
+ }
+ }
+
+ if (autoscrollRenderer()) {
+ if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
+ autoscrollRenderer()->stopAutoscroll();
+#if ENABLE(PAN_SCROLLING)
+ if (m_panScrollInProgress) {
+ m_frame->view()->removePanScrollIcon();
+ m_frame->view()->setCursor(pointerCursor());
+ }
+#endif
+
+ setAutoscrollRenderer(0);
}
- if (!rendererIsBeingDestroyed && autoscrollRenderer())
- autoscrollRenderer()->stopAutoscroll();
- setAutoscrollRenderer(0);
m_autoscrollTimer.stop();
+
+ m_panScrollInProgress = false;
+ // If we're not in the top frame we notify it that we are not using the panScroll anymore
+ if (m_frame->page() && m_frame != m_frame->page()->mainFrame())
+ m_frame->page()->mainFrame()->eventHandler()->setPanScrollInProgress(false);
+ m_autoscrollInProgress = false;
}
Node* EventHandler::mousePressNode() const
@@ -652,6 +804,13 @@ IntPoint EventHandler::currentMousePosition() const
return m_currentMousePosition;
}
+Frame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
+{
+ if (!hitTestResult.isOverWidget())
+ return 0;
+ return subframeForTargetNode(hitTestResult.targetNode());
+}
+
Frame* subframeForTargetNode(Node* node)
{
if (!node)
@@ -677,37 +836,42 @@ static bool isSubmitImage(Node* node)
// Returns true if the node's editable block is not current focused for editing
static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
{
- return frame->selectionController()->rootEditableElement() != node->rootEditableElement();
+ return frame->selection()->rootEditableElement() != node->rootEditableElement();
}
-Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, PlatformScrollbar* scrollbar)
+Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
{
// 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->selectionController()->isCaretOrRange() && !m_capturingMouseEventsNode)
+ if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
return iBeamCursor();
Node* node = event.targetNode();
RenderObject* renderer = node ? node->renderer() : 0;
RenderStyle* style = renderer ? renderer->style() : 0;
+ if (renderer && renderer->isFrameSet()) {
+ RenderFrameSet* fs = static_cast<RenderFrameSet*>(renderer);
+ if (fs->canResizeRow(event.localPoint()))
+ return rowResizeCursor();
+ if (fs->canResizeColumn(event.localPoint()))
+ return columnResizeCursor();
+ }
+
if (style && style->cursors()) {
const CursorList* cursors = style->cursors();
for (unsigned i = 0; i < cursors->size(); ++i) {
- CachedImage* cimage = (*cursors)[i].cursorImage;
+ CachedImage* cimage = (*cursors)[i].cursorImage.get();
IntPoint hotSpot = (*cursors)[i].hotSpot;
-#if ENABLE(SVG)
- if (!cimage) {
- Element* e = node->document()->getElementById((*cursors)[i].cursorFragmentId);
- if (e && e->hasTagName(cursorTag)) {
- hotSpot.setX(int(static_cast<SVGCursorElement*>(e)->x().value()));
- hotSpot.setY(int(static_cast<SVGCursorElement*>(e)->y().value()));
- cimage = static_cast<SVGCursorElement*>(e)->cachedImage();
- }
- }
-#endif
if (!cimage)
continue;
+ // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
+ IntSize size = cimage->image()->size();
+ if (size.width() > 128 || size.height() > 128)
+ continue;
+ // Do not let the hotspot be outside the bounds of the image.
+ if (hotSpot.x() < 0 || hotSpot.y() < 0 || hotSpot.x() > size.width() || hotSpot.y() > size.height())
+ continue;
if (cimage->image()->isNull())
break;
if (!cimage->errorOccurred())
@@ -820,6 +984,10 @@ Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Pla
return zoomInCursor();
case CURSOR_WEBKIT_ZOOM_OUT:
return zoomOutCursor();
+ case CURSOR_WEBKIT_GRAB:
+ return grabCursor();
+ case CURSOR_WEBKIT_GRABBING:
+ return grabbingCursor();
}
return pointerCursor();
}
@@ -839,7 +1007,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
m_mouseDownMayStartAutoscroll = false;
m_mouseDownPos = m_frame->view()->windowToContents(mouseEvent.pos());
m_mouseDownWasInSubframe = false;
-
+
MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent);
if (!mev.targetNode()) {
@@ -849,7 +1017,14 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
m_mousePressNode = mev.targetNode();
- Frame* subframe = subframeForTargetNode(mev.targetNode());
+ InspectorController* inspector = m_frame->page()->inspectorController();
+ if (inspector && inspector->enabled() && inspector->searchingForNodeInPage()) {
+ inspector->handleMousePressOnNode(m_mousePressNode.get());
+ invalidateClick();
+ return true;
+ }
+
+ Frame* subframe = subframeForHitTestResult(mev);
if (subframe && passMousePressEventToSubframe(mev, subframe)) {
// Start capturing future events for this frame. We only do this if we didn't clear
// the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
@@ -859,6 +1034,32 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
return true;
}
+#if ENABLE(PAN_SCROLLING)
+ if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
+ stopAutoscrollTimer();
+ invalidateClick();
+ return true;
+ }
+
+ if (mouseEvent.button() == MiddleButton && !mev.isOverLink()) {
+ RenderObject* renderer = mev.targetNode()->renderer();
+
+ while (renderer && !renderer->canBeProgramaticallyScrolled(false)) {
+ if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
+ renderer = renderer->document()->ownerElement()->renderer();
+ else
+ renderer = renderer->parent();
+ }
+
+ if (renderer) {
+ m_panScrollInProgress = true;
+ handleAutoscroll(renderer);
+ invalidateClick();
+ return true;
+ }
+ }
+#endif
+
m_clickCount = mouseEvent.clickCount();
m_clickNode = mev.targetNode();
@@ -872,7 +1073,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
return true;
}
- bool swallowEvent = dispatchMouseEvent(mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+ bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
// If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
// in case the scrollbar widget was destroyed when the mouse event was handled.
@@ -896,7 +1097,7 @@ bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
if (mev.targetNode()->isShadowNode() && mev.targetNode()->shadowParentNode()->hasTagName(inputTag))
mev = prepareMouseEvent(HitTestRequest(true, true), mouseEvent);
- PlatformScrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent);
+ Scrollbar* scrollbar = m_frame->view()->scrollbarUnderMouse(mouseEvent);
if (!scrollbar)
scrollbar = mev.scrollbar();
if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
@@ -921,20 +1122,23 @@ bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEv
m_currentMousePosition = mouseEvent.pos();
MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, true), mouseEvent);
- Frame* subframe = subframeForTargetNode(mev.targetNode());
+ Frame* subframe = subframeForHitTestResult(mev);
if (subframe && passMousePressEventToSubframe(mev, subframe)) {
m_capturingMouseEventsNode = 0;
return true;
}
m_clickCount = mouseEvent.clickCount();
- bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
bool swallowClickEvent = false;
// Don't ever dispatch click events for right clicks
if (mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
- swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+ swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+ if (m_lastScrollbarUnderMouse)
+ swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
+
bool swallowMouseReleaseEvent = false;
if (!swallowMouseUpEvent)
swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
@@ -983,11 +1187,11 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
#endif
if (m_frameSetBeingResized)
- return dispatchMouseEvent(mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
+ return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
// Send events right to a scrollbar if the mouse is pressed.
if (m_lastScrollbarUnderMouse && m_mousePressed)
- return m_lastScrollbarUnderMouse->handleMouseMoveEvent(mouseEvent);
+ return m_lastScrollbarUnderMouse->mouseMoved(m_lastScrollbarUnderMouse->transformEvent(mouseEvent));
// Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
// if we are allowed to select.
@@ -998,7 +1202,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
if (hoveredNode)
*hoveredNode = mev.hitTestResult();
- PlatformScrollbar* scrollbar = 0;
+ Scrollbar* scrollbar = 0;
if (m_resizeLayer && m_resizeLayer->inResizeMode())
m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
@@ -1012,15 +1216,14 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
if (m_lastScrollbarUnderMouse != scrollbar) {
// Send mouse exited to the old scrollbar.
if (m_lastScrollbarUnderMouse)
- m_lastScrollbarUnderMouse->handleMouseOutEvent(mouseEvent);
+ m_lastScrollbarUnderMouse->mouseExited();
m_lastScrollbarUnderMouse = m_mousePressed ? 0 : scrollbar;
}
}
bool swallowEvent = false;
- Node* targetNode = m_capturingMouseEventsNode ? m_capturingMouseEventsNode.get() : mev.targetNode();
- RefPtr<Frame> newSubframe = subframeForTargetNode(targetNode);
-
+ RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
+
// We want mouseouts to happen first, from the inside out. First send a move event to the last subframe so that it will fire mouseouts.
if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
@@ -1028,11 +1231,15 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
if (newSubframe) {
// Update over/out state before passing the event to the subframe.
updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
- swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
+
+ // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
+ // node to be detached from its FrameView, in which case the event should not be passed.
+ if (newSubframe->view())
+ swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
} else {
if (scrollbar && !m_mousePressed)
- scrollbar->handleMouseMoveEvent(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
- if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && m_frame->view())
+ scrollbar->mouseMoved(scrollbar->transformEvent(mouseEvent)); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
+ if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() && m_frame->view())
m_frame->view()->setCursor(selectCursor(mev, scrollbar));
}
@@ -1041,7 +1248,7 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, Hi
if (swallowEvent)
return true;
- swallowEvent = dispatchMouseEvent(mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
+ swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, mev.targetNode(), false, 0, mouseEvent, true);
if (!swallowEvent)
swallowEvent = handleMouseDraggedEvent(mev);
@@ -1073,27 +1280,26 @@ bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
#endif
if (m_frameSetBeingResized)
- return dispatchMouseEvent(mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
+ return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
if (m_lastScrollbarUnderMouse) {
invalidateClick();
- return m_lastScrollbarUnderMouse->handleMouseReleaseEvent(mouseEvent);
+ return m_lastScrollbarUnderMouse->mouseUp();
}
MouseEventWithHitTestResults mev = prepareMouseEvent(HitTestRequest(false, false, false, true), mouseEvent);
- Node* targetNode = m_capturingMouseEventsNode.get() ? m_capturingMouseEventsNode.get() : mev.targetNode();
- Frame* subframe = subframeForTargetNode(targetNode);
+ Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
if (subframe && passMouseReleaseEventToSubframe(mev, subframe)) {
m_capturingMouseEventsNode = 0;
return true;
}
- bool swallowMouseUpEvent = dispatchMouseEvent(mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
+ bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, mev.targetNode(), true, m_clickCount, mouseEvent, false);
// Don't ever dispatch click events for right clicks
bool swallowClickEvent = false;
if (m_clickCount > 0 && mouseEvent.button() != RightButton && mev.targetNode() == m_clickNode)
- swallowClickEvent = dispatchMouseEvent(clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
+ swallowClickEvent = dispatchMouseEvent(eventNames().clickEvent, mev.targetNode(), true, m_clickCount, mouseEvent, true);
if (m_resizeLayer) {
m_resizeLayer->setInResizeMode(false);
@@ -1113,14 +1319,14 @@ bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTa
{
IntPoint contentsPos = m_frame->view()->windowToContents(event.pos());
- RefPtr<MouseEvent> me = new MouseEvent(eventType,
+ RefPtr<MouseEvent> me = MouseEvent::create(eventType,
true, true, m_frame->document()->defaultView(),
0, event.globalX(), event.globalY(), contentsPos.x(), contentsPos.y(),
event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
0, 0, clipboard);
ExceptionCode ec = 0;
- EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec, true);
+ EventTargetNodeCast(dragTarget)->dispatchEvent(me.get(), ec);
return me->defaultPrevented();
}
@@ -1151,7 +1357,7 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
else
- accept = dispatchDragEvent(dragenterEvent, newTarget, event, clipboard);
+ accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
if (m_dragTarget) {
Frame* frame = (m_dragTarget->hasTagName(frameTag) || m_dragTarget->hasTagName(iframeTag))
@@ -1159,14 +1365,14 @@ bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard*
if (frame)
accept = frame->eventHandler()->updateDragAndDrop(event, clipboard);
else
- dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, clipboard);
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
}
} else {
if (newTarget)
if (newTarget->hasTagName(frameTag) || newTarget->hasTagName(iframeTag))
accept = static_cast<HTMLFrameElementBase*>(newTarget)->contentFrame()->eventHandler()->updateDragAndDrop(event, clipboard);
else
- accept = dispatchDragEvent(dragoverEvent, newTarget, event, clipboard);
+ accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
}
m_dragTarget = newTarget;
@@ -1181,7 +1387,7 @@ void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard*
if (frame)
frame->eventHandler()->cancelDragAndDrop(event, clipboard);
else
- dispatchDragEvent(dragleaveEvent, m_dragTarget.get(), event, clipboard);
+ dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
}
clearDragState();
}
@@ -1195,7 +1401,7 @@ bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard
if (frame)
accept = frame->eventHandler()->performDragAndDrop(event, clipboard);
else
- accept = dispatchDragEvent(dropEvent, m_dragTarget.get(), event, clipboard);
+ accept = dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
}
clearDragState();
return accept;
@@ -1210,11 +1416,6 @@ void EventHandler::clearDragState()
#endif
}
-Node* EventHandler::nodeUnderMouse() const
-{
- return m_nodeUnderMouse.get();
-}
-
void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
{
m_capturingMouseEventsNode = n;
@@ -1229,6 +1430,25 @@ MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestReques
return m_frame->document()->prepareMouseEvent(request, documentPoint, mev);
}
+#if ENABLE(SVG)
+static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
+{
+ if (!referenceNode || !referenceNode->isSVGElement())
+ return 0;
+
+ Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
+ if (!shadowTreeElement)
+ return 0;
+
+ Node* shadowTreeParentElement = shadowTreeElement->shadowParentNode();
+ if (!shadowTreeParentElement)
+ return 0;
+
+ ASSERT(shadowTreeParentElement->hasTagName(useTag));
+ return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
+}
+#endif
+
void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
{
Node* result = targetNode;
@@ -1244,23 +1464,63 @@ void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMo
result = result->shadowAncestorNode();
}
m_nodeUnderMouse = result;
-
+#if ENABLE(SVG)
+ m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
+
+ // <use> shadow tree elements may have been recloned, update node under mouse in any case
+ if (m_lastInstanceUnderMouse) {
+ SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
+ SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
+
+ if (lastCorrespondingElement && lastCorrespondingUseElement) {
+ HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
+
+ // Locate the recloned shadow tree element for our corresponding instance
+ HashSet<SVGElementInstance*>::iterator end = instances.end();
+ for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
+ SVGElementInstance* instance = (*it);
+ ASSERT(instance->correspondingElement() == lastCorrespondingElement);
+
+ if (instance == m_lastInstanceUnderMouse)
+ continue;
+
+ if (instance->correspondingUseElement() != lastCorrespondingUseElement)
+ continue;
+
+ SVGElement* shadowTreeElement = instance->shadowTreeElement();
+ if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
+ continue;
+
+ m_lastNodeUnderMouse = shadowTreeElement;
+ m_lastInstanceUnderMouse = instance;
+ break;
+ }
+ }
+ }
+#endif
+
// Fire mouseout/mouseover if the mouse has shifted to a different node.
if (fireMouseOverOut) {
if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
m_lastNodeUnderMouse = 0;
m_lastScrollbarUnderMouse = 0;
+#if ENABLE(SVG)
+ m_lastInstanceUnderMouse = 0;
+#endif
}
if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
// send mouseout event to the old node
if (m_lastNodeUnderMouse)
- EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, mouseoutEvent, 0, m_nodeUnderMouse.get());
+ EventTargetNodeCast(m_lastNodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
// send mouseover event to the new node
if (m_nodeUnderMouse)
- EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, mouseoverEvent, 0, m_lastNodeUnderMouse.get());
+ EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
}
m_lastNodeUnderMouse = m_nodeUnderMouse;
+#if ENABLE(SVG)
+ m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
+#endif
}
}
@@ -1273,7 +1533,7 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe
if (m_nodeUnderMouse)
swallowEvent = EventTargetNodeCast(m_nodeUnderMouse.get())->dispatchMouseEvent(mouseEvent, eventType, clickCount);
- if (!swallowEvent && eventType == mousedownEvent) {
+ if (!swallowEvent && eventType == eventNames().mousedownEvent) {
// Blur current focus node when a link/button is clicked; this
// is expected by some sites that rely on onChange handlers running
// from form fields before the button click is processed.
@@ -1291,8 +1551,8 @@ bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targe
// will set a selection inside it, which will call setFocuseNodeIfNeeded.
ExceptionCode ec = 0;
Node* n = node->isShadowNode() ? node->shadowParentNode() : node;
- if (m_frame->selectionController()->isRange() &&
- m_frame->selectionController()->toRange()->compareNode(n, ec) == Range::NODE_INSIDE &&
+ if (m_frame->selection()->isRange() &&
+ m_frame->selection()->toRange()->compareNode(n, ec) == Range::NODE_INSIDE &&
n->isDescendantOf(m_frame->document()->focusedNode()))
return false;
@@ -1336,7 +1596,7 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
// Figure out which view to send the event to.
RenderObject* target = node->renderer();
- if (target && target->isWidget()) {
+ if (result.isOverWidget() && target && target->isWidget()) {
Widget* widget = static_cast<RenderWidget*>(target)->widget();
if (widget && passWheelEventToWidget(e, widget)) {
@@ -1353,14 +1613,8 @@ bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
if (node->renderer()) {
// Just 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).
- float deltaX = e.isContinuous() ? e.continuousDeltaX() : e.deltaX();
- float deltaY = e.isContinuous() ? e.continuousDeltaY() : e.deltaY();
- if (deltaX && node->renderer()->scroll(deltaX < 0 ? ScrollRight : ScrollLeft, e.isContinuous() ? ScrollByPixel : ScrollByLine,
- deltaX < 0 ? -deltaX : deltaX))
- e.accept();
- if (deltaY && node->renderer()->scroll(deltaY < 0 ? ScrollDown : ScrollUp, e.isContinuous() ? ScrollByPixel : ScrollByLine,
- deltaY < 0 ? -deltaY : deltaY))
- e.accept();
+ scrollAndAcceptEvent(e.deltaX(), ScrollLeft, ScrollRight, e, node);
+ scrollAndAcceptEvent(e.deltaY(), ScrollUp, ScrollDown, e, node);
}
}
@@ -1381,16 +1635,19 @@ bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
IntPoint viewportPos = v->windowToContents(event.pos());
MouseEventWithHitTestResults mev = doc->prepareMouseEvent(HitTestRequest(false, true), viewportPos, event);
- if (!m_frame->selectionController()->contains(viewportPos) &&
+ // Context menu events shouldn't select text in GTK+ applications.
+#if !PLATFORM(GTK)
+ if (!m_frame->selection()->contains(viewportPos) &&
// FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
// If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
// available for text selections. But only if we're above text.
- (m_frame->selectionController()->isContentEditable() || mev.targetNode() && mev.targetNode()->isTextNode())) {
+ (m_frame->selection()->isContentEditable() || mev.targetNode() && mev.targetNode()->isTextNode())) {
m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
selectClosestWordOrLinkFromMouseEvent(mev);
}
+#endif
- swallowEvent = dispatchMouseEvent(contextmenuEvent, mev.targetNode(), true, 0, event, true);
+ swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, mev.targetNode(), true, 0, event, true);
return swallowEvent;
}
@@ -1413,7 +1670,7 @@ bool EventHandler::canMouseDownStartSelect(Node* node)
for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
if (Node* node = curr->element())
- return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
+ return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true);
return true;
}
@@ -1425,7 +1682,7 @@ bool EventHandler::canMouseDragExtendSelect(Node* node)
for (RenderObject* curr = node->renderer(); curr; curr = curr->parent())
if (Node* node = curr->element())
- return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
+ return EventTargetNodeCast(node)->dispatchEventForType(eventNames().selectstartEvent, true, true);
return true;
}
@@ -1448,7 +1705,7 @@ void EventHandler::hoverTimerFired(Timer<EventHandler>*)
ASSERT(m_frame);
ASSERT(m_frame->document());
- if (RenderObject* renderer = m_frame->renderer()) {
+ if (RenderObject* renderer = m_frame->contentRenderer()) {
HitTestResult result(m_frame->view()->windowToContents(m_currentMousePosition));
renderer->layer()->hitTest(HitTestRequest(false, false, true), result);
m_frame->document()->updateRendering();
@@ -1473,21 +1730,14 @@ static EventTargetNode* eventTargetNodeForDocument(Document* doc)
bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
{
-#if PLATFORM(MAC) || PLATFORM(QT)
- if (evt.ctrlKey())
-#else
- if (evt.altKey())
-#endif
- {
- String key = evt.unmodifiedText();
- Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
- if (elem) {
- elem->accessKeyAction(false);
- return true;
- }
- }
-
- return false;
+ if ((evt.modifiers() & s_accessKeyModifiers) != s_accessKeyModifiers)
+ return false;
+ String key = evt.unmodifiedText();
+ Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
+ if (!elem)
+ return false;
+ elem->accessKeyAction(false);
+ return true;
}
#if !PLATFORM(MAC)
@@ -1499,6 +1749,18 @@ bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
{
+#if ENABLE(PAN_SCROLLING)
+ if (m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
+ String escKeyId = "U+001B";
+ // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
+ if (initialKeyEvent.keyIdentifier() == escKeyId && initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp)
+ stopAutoscrollTimer();
+
+ // If we were in autoscroll/panscroll mode, we swallow the key event
+ return true;
+ }
+#endif
+
// Check for cases where we are too early for events -- possible unmatched key up
// from pressing return in the location bar.
RefPtr<EventTargetNode> node = eventTargetNodeForDocument(m_frame->document());
@@ -1527,13 +1789,13 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
- RefPtr<KeyboardEvent> keydown = new KeyboardEvent(keyDownEvent, m_frame->document()->defaultView());
+ RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
if (matchedAnAccessKey)
keydown->setDefaultPrevented(true);
keydown->setTarget(node);
if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
- node->dispatchEvent(keydown, ec, true);
+ node->dispatchEvent(keydown, ec);
return keydown->defaultHandled() || keydown->defaultPrevented();
}
@@ -1548,12 +1810,12 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
if (handledByInputMethod) {
keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
- keydown = new KeyboardEvent(keyDownEvent, m_frame->document()->defaultView());
+ keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
keydown->setTarget(node);
keydown->setDefaultHandled();
}
- node->dispatchEvent(keydown, ec, true);
+ node->dispatchEvent(keydown, ec);
bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented();
if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
return keydownResult;
@@ -1570,28 +1832,59 @@ bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
if (keyPressEvent.text().isEmpty())
return keydownResult;
- RefPtr<KeyboardEvent> keypress = new KeyboardEvent(keyPressEvent, m_frame->document()->defaultView());
+ RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
keypress->setTarget(node);
if (keydownResult)
keypress->setDefaultPrevented(true);
#if PLATFORM(MAC)
keypress->keypressCommands() = keydown->keypressCommands();
#endif
- node->dispatchEvent(keypress, ec, true);
+ node->dispatchEvent(keypress, ec);
return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
}
+void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
+{
+ if (!event)
+ return;
+
+ String key = event->keyIdentifier();
+ bool isShifted = event->getModifierState("Shift");
+ bool isOptioned = event->getModifierState("Alt");
+
+ if (key == "Up") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Down") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Left") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::LEFT, (isOptioned) ? WordGranularity : CharacterGranularity, true);
+ event->setDefaultHandled();
+ }
+ else if (key == "Right") {
+ m_frame->selection()->modify((isShifted) ? SelectionController::EXTEND : SelectionController::MOVE, SelectionController::RIGHT, (isOptioned) ? WordGranularity : CharacterGranularity, true);
+ event->setDefaultHandled();
+ }
+}
+
void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
{
- if (event->type() == keydownEvent) {
+ if (event->type() == eventNames().keydownEvent) {
m_frame->editor()->handleKeyboardEvent(event);
if (event->defaultHandled())
return;
if (event->keyIdentifier() == "U+0009")
defaultTabEventHandler(event);
+
+ // provides KB navigation and selection for enhanced accessibility users
+ if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
+ handleKeyboardSelectionMovement(event);
}
- if (event->type() == keypressEvent) {
+ if (event->type() == eventNames().keypressEvent) {
m_frame->editor()->handleKeyboardEvent(event);
if (event->defaultHandled())
return;
@@ -1638,7 +1931,7 @@ void EventHandler::dragSourceMovedTo(const PlatformMouseEvent& event)
{
if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
// for now we don't care if event handler cancels default behavior, since there is none
- dispatchDragSrcEvent(dragEvent, event);
+ dispatchDragSrcEvent(eventNames().dragEvent, event);
}
void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
@@ -1646,7 +1939,7 @@ void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperat
if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
dragState().m_dragClipboard->setDestinationOperation(operation);
// for now we don't care if event handler cancels default behavior, since there is none
- dispatchDragSrcEvent(dragendEvent, event);
+ dispatchDragSrcEvent(eventNames().dragendEvent, event);
}
freeClipboard();
dragState().m_dragSrc = 0;
@@ -1684,7 +1977,7 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
// try to find an element that wants to be dragged
HitTestRequest request(true, false);
HitTestResult result(m_mouseDownPos);
- m_frame->renderer()->layer()->hitTest(request, result);
+ m_frame->contentRenderer()->layer()->hitTest(request, result);
Node* node = result.innerNode();
if (node && node->renderer())
dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
@@ -1702,7 +1995,7 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
node = result.innerNonSharedNode();
dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
- dragState().m_dragSrcInSelection = m_frame->selectionController()->contains(m_mouseDownPos);
+ dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
}
}
@@ -1739,13 +2032,20 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
// image and offset
if (dragState().m_dragSrcIsDHTML) {
int srcX, srcY;
- dragState().m_dragSrc->renderer()->absolutePosition(srcX, srcY);
- IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY);
- dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta);
+ if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
+ renderer->absolutePosition(srcX, srcY);
+ IntSize delta = m_mouseDownPos - IntPoint(srcX, srcY);
+ dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint() + delta);
+ } else {
+ // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
+ // the element in some way. In this case we just kill the drag.
+ m_mouseDownMayStartDrag = false;
+ goto cleanupDrag;
+ }
}
- m_mouseDownMayStartDrag = dispatchDragSrcEvent(dragstartEvent, m_mouseDown)
- && !m_frame->selectionController()->isInPasswordField();
+ m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
+ && !m_frame->selection()->isInPasswordField();
// Invalidate clipboard here against anymore pasteboard writing for security. The drag
// image can still be changed as we drag, but not the pasteboard data.
@@ -1767,11 +2067,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
// Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
- dispatchDragSrcEvent(dragendEvent, event.event());
+ dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
m_mouseDownMayStartDrag = false;
}
}
-
+
+cleanupDrag:
if (!m_mouseDownMayStartDrag) {
// something failed to start the drag, cleanup
freeClipboard();
@@ -1791,7 +2092,7 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve
// Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
// and avoid dispatching text input events from keydown default handlers.
if (underlyingEvent && underlyingEvent->isKeyboardEvent())
- ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == keypressEvent);
+ ASSERT(static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
#endif
EventTarget* target;
if (underlyingEvent)
@@ -1800,12 +2101,12 @@ bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEve
target = eventTargetNodeForDocument(m_frame->document());
if (!target)
return false;
- RefPtr<TextEvent> event = new TextEvent(m_frame->domWindow(), text);
+ RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text);
event->setUnderlyingEvent(underlyingEvent);
event->setIsLineBreak(isLineBreak);
event->setIsBackTab(isBackTab);
ExceptionCode ec;
- return target->dispatchEvent(event.release(), ec, true);
+ return target->dispatchEvent(event.release(), ec);
}
@@ -1873,6 +2174,175 @@ void EventHandler::capsLockStateMayHaveChanged()
if (Node* node = d->focusedNode())
if (RenderObject* r = node->renderer())
r->capsLockStateMayHaveChanged();
-}
+}
+
+unsigned EventHandler::pendingFrameUnloadEventCount()
+{
+ return m_pendingFrameUnloadEventCount;
+}
+
+void EventHandler::addPendingFrameUnloadEventCount()
+{
+ m_pendingFrameUnloadEventCount += 1;
+ m_frame->page()->changePendingUnloadEventCount(1);
+ return;
+}
+
+void EventHandler::removePendingFrameUnloadEventCount()
+{
+ ASSERT( (-1 + (int)m_pendingFrameUnloadEventCount) >= 0 );
+ m_pendingFrameUnloadEventCount -= 1;
+ m_frame->page()->changePendingUnloadEventCount(-1);
+ return;
+}
+
+void EventHandler::clearPendingFrameUnloadEventCount()
+{
+ m_frame->page()->changePendingUnloadEventCount(-((int)m_pendingFrameUnloadEventCount));
+ m_pendingFrameUnloadEventCount = 0;
+ return;
+}
+
+unsigned EventHandler::pendingFrameBeforeUnloadEventCount()
+{
+ return m_pendingFrameBeforeUnloadEventCount;
+}
+
+void EventHandler::addPendingFrameBeforeUnloadEventCount()
+{
+ m_pendingFrameBeforeUnloadEventCount += 1;
+ m_frame->page()->changePendingBeforeUnloadEventCount(1);
+ return;
+}
+
+void EventHandler::removePendingFrameBeforeUnloadEventCount()
+{
+ ASSERT( (-1 + (int)m_pendingFrameBeforeUnloadEventCount) >= 0 );
+ m_pendingFrameBeforeUnloadEventCount -= 1;
+ m_frame->page()->changePendingBeforeUnloadEventCount(-1);
+ return;
+}
+
+ void EventHandler::clearPendingFrameBeforeUnloadEventCount()
+{
+ m_frame->page()->changePendingBeforeUnloadEventCount(-((int)m_pendingFrameBeforeUnloadEventCount));
+ m_pendingFrameBeforeUnloadEventCount = 0;
+ return;
+}
+
+bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
+{
+ if (!scrollbar || !scrollbar->enabled())
+ return false;
+ return scrollbar->mouseDown(mev.event());
+}
+
+#if ENABLE(TOUCH_EVENTS) // Android
+bool EventHandler::handleTouchEvent(const PlatformTouchEvent& e)
+{
+ // only handle the touch event in the top frame handler
+ if (m_frame->tree()->parent(true))
+ return m_frame->tree()->parent()->eventHandler()->handleTouchEvent(e);
+
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+
+ RenderObject* docRenderer = doc->renderer();
+ if (!docRenderer)
+ return false;
+
+ if (doc->touchEventListeners().size() == 0)
+ return false;
+
+ TouchEventType type = e.eventType();
+ if (type == TouchEventStart) {
+ Frame* frame = m_frame;
+ IntPoint vPoint = frame->view()->windowToContents(e.pos());
+ HitTestRequest request(true, false);
+ HitTestResult result(vPoint);
+ frame->contentRenderer()->layer()->hitTest(request, result);
+ Node* node = result.innerNode();
+ if (node) {
+ RenderObject* target = node->renderer();
+ while (target && target->isWidget()) {
+ Widget* widget = static_cast<RenderWidget*>(target)->widget();
+ if (widget->isFrameView()) {
+ frame = static_cast<FrameView*>(widget)->frame();
+ vPoint = frame->view()->windowToContents(e.pos());
+ HitTestResult ret(vPoint);
+ frame->contentRenderer()->layer()->hitTest(request, ret);
+ node = ret.innerNode();
+ if (!node)
+ break;
+ else
+ target = node->renderer();
+ } else
+ // plugin view??
+ break;
+ }
+ }
+
+ if (!node || !node->isEventTargetNode()) {
+ // reset to the top document node
+ node = doc;
+ frame = m_frame;
+ vPoint = frame->view()->windowToContents(e.pos());
+ }
+
+ m_touch = Touch::create(frame, EventTargetNodeCast(node), 0,
+ e.x(), e.y(), vPoint.x(), vPoint.y());
+ } else if (m_touch) {
+ if ((type == TouchEventMove) && (e.x() == m_touch->screenX()) &&
+ (e.y() == m_touch->screenY())) {
+ // don't trigger the event if it hasn't really moved
+ return false;
+ }
+
+ IntPoint vPoint = m_touch->frame()->view()->windowToContents(e.pos());
+ m_touch->updateLocation(e.x(), e.y(), vPoint.x(), vPoint.y());
+ } else {
+ return false;
+ }
+
+ RefPtr<TouchList> touchList = TouchList::create();
+ touchList->append(m_touch);
+ RefPtr<TouchEvent> te;
+ switch(type) {
+ case TouchEventStart:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchstartEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventEnd:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchendEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventMove:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchmoveEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ case TouchEventCancel:
+ te = TouchEvent::create(touchList.get(), touchList.get(), touchList.get(),
+ eventNames().touchcancelEvent, m_touch->frame()->document()->defaultView(),
+ m_touch->screenX(), m_touch->screenY(), m_touch->pageX(), m_touch->pageY());
+ break;
+
+ default:
+ return false;
+ }
+ ExceptionCode ec = 0;
+ static_cast<EventTargetNode*>(m_touch->target())->dispatchEvent(te.get(), ec);
+ if (type == TouchEventEnd || type == TouchEventCancel) {
+ m_touch = 0;
+ }
+ return te->defaultPrevented();
+}
+#endif
}