1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "EventHandler.h"
29
30 #include "AXObjectCache.h"
31 #include "CachedImage.h"
32 #include "Chrome.h"
33 #include "ChromeClient.h"
34 #include "Cursor.h"
35 #include "CursorList.h"
36 #include "Document.h"
37 #include "DragController.h"
38 #include "Editor.h"
39 #include "EventNames.h"
40 #include "EventQueue.h"
41 #include "FloatPoint.h"
42 #include "FloatRect.h"
43 #include "FocusController.h"
44 #include "Frame.h"
45 #include "FrameLoader.h"
46 #include "FrameTree.h"
47 #include "FrameView.h"
48 #include "htmlediting.h"
49 #include "HTMLFrameElementBase.h"
50 #include "HTMLFrameSetElement.h"
51 #include "HTMLInputElement.h"
52 #include "HTMLNames.h"
53 #include "HitTestRequest.h"
54 #include "HitTestResult.h"
55 #include "Image.h"
56 #include "InspectorInstrumentation.h"
57 #include "KeyboardEvent.h"
58 #include "MouseEvent.h"
59 #include "MouseEventWithHitTestResults.h"
60 #include "Page.h"
61 #include "PlatformKeyboardEvent.h"
62 #include "PlatformWheelEvent.h"
63 #include "PluginDocument.h"
64 #if defined(ANDROID_PLUGINS)
65 #include "PluginView.h"
66 #endif
67 #include "RenderFrameSet.h"
68 #include "RenderLayer.h"
69 #include "RenderTextControlSingleLine.h"
70 #include "RenderView.h"
71 #include "RenderWidget.h"
72 #include "ScrollAnimator.h"
73 #include "Scrollbar.h"
74 #include "SelectionController.h"
75 #include "Settings.h"
76 #include "StyleCachedImage.h"
77 #include "TextEvent.h"
78 #include "TextIterator.h"
79 #include "UserGestureIndicator.h"
80 #include "UserTypingGestureIndicator.h"
81 #include "WheelEvent.h"
82 #include "WindowsKeyboardCodes.h"
83 #include <wtf/CurrentTime.h>
84 #include <wtf/StdLibExtras.h>
85
86 #if ENABLE(GESTURE_EVENTS)
87 #include "PlatformGestureEvent.h"
88 #endif
89
90 #if ENABLE(SVG)
91 #include "SVGDocument.h"
92 #include "SVGElementInstance.h"
93 #include "SVGNames.h"
94 #include "SVGUseElement.h"
95 #endif
96
97 #if ENABLE(TOUCH_EVENTS)
98 #include "PlatformTouchEvent.h"
99 #include "TouchEvent.h"
100 #endif
101
102 #if ENABLE(GESTURE_RECOGNIZER)
103 #include "PlatformGestureRecognizer.h"
104 #endif
105
106 #if defined(ANDROID_PLUGINS)
107 #include "WebViewCore.h"
108 #endif
109
110 namespace WebCore {
111
112 using namespace HTMLNames;
113
114 #if ENABLE(DRAG_SUPPORT)
115 // The link drag hysteresis is much larger than the others because there
116 // needs to be enough space to cancel the link press without starting a link drag,
117 // and because dragging links is rare.
118 const int LinkDragHysteresis = 40;
119 const int ImageDragHysteresis = 5;
120 const int TextDragHysteresis = 3;
121 const int GeneralDragHysteresis = 3;
122 #endif // ENABLE(DRAG_SUPPORT)
123
124 // Match key code of composition keydown event on windows.
125 // IE sends VK_PROCESSKEY which has value 229;
126 const int CompositionEventKeyCode = 229;
127
128 #if ENABLE(SVG)
129 using namespace SVGNames;
130 #endif
131
132 // When the autoscroll or the panScroll is triggered when do the scroll every 0.05s to make it smooth
133 const double autoscrollInterval = 0.05;
134
135 const double fakeMouseMoveInterval = 0.1;
136
scrollNode(float delta,WheelEvent::Granularity granularity,ScrollDirection positiveDirection,ScrollDirection negativeDirection,Node * node,Node ** stopNode)137 static inline bool scrollNode(float delta, WheelEvent::Granularity granularity, ScrollDirection positiveDirection, ScrollDirection negativeDirection, Node* node, Node** stopNode)
138 {
139 if (!delta)
140 return false;
141
142 if (!node->renderer())
143 return false;
144
145 // Find the nearest enclosing box.
146 RenderBox* enclosingBox = node->renderer()->enclosingBox();
147
148 float absDelta = delta > 0 ? delta : -delta;
149
150 if (granularity == WheelEvent::Page)
151 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPage, absDelta, stopNode);
152
153 if (granularity == WheelEvent::Line)
154 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByLine, absDelta, stopNode);
155
156 if (granularity == WheelEvent::Pixel)
157 return enclosingBox->scroll(delta < 0 ? negativeDirection : positiveDirection, ScrollByPixel, absDelta, stopNode);
158
159 return false;
160 }
161
162 #if !PLATFORM(MAC)
163
eventLoopHandleMouseUp(const MouseEventWithHitTestResults &)164 inline bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
165 {
166 return false;
167 }
168
169 #if ENABLE(DRAG_SUPPORT)
eventLoopHandleMouseDragged(const MouseEventWithHitTestResults &)170 inline bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
171 {
172 return false;
173 }
174 #endif
175
176 #endif
177
EventHandler(Frame * frame)178 EventHandler::EventHandler(Frame* frame)
179 : m_frame(frame)
180 , m_mousePressed(false)
181 , m_capturesDragging(false)
182 , m_mouseDownMayStartSelect(false)
183 #if ENABLE(DRAG_SUPPORT)
184 , m_mouseDownMayStartDrag(false)
185 #endif
186 , m_mouseDownWasSingleClickInSelection(false)
187 , m_beganSelectingText(false)
188 , m_panScrollInProgress(false)
189 , m_panScrollButtonPressed(false)
190 , m_springLoadedPanScrollInProgress(false)
191 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
192 , m_autoscrollTimer(this, &EventHandler::autoscrollTimerFired)
193 , m_autoscrollRenderer(0)
194 , m_autoscrollInProgress(false)
195 , m_mouseDownMayStartAutoscroll(false)
196 , m_mouseDownWasInSubframe(false)
197 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
198 #if ENABLE(SVG)
199 , m_svgPan(false)
200 #endif
201 , m_resizeLayer(0)
202 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
203 , m_clickCount(0)
204 , m_mouseDownTimestamp(0)
205 , m_useLatchedWheelEventNode(false)
206 , m_widgetIsLatched(false)
207 #if PLATFORM(MAC)
208 , m_mouseDownView(nil)
209 , m_sendingEventToSubview(false)
210 , m_activationEventNumber(-1)
211 #endif
212 #if ENABLE(TOUCH_EVENTS)
213 , m_touchPressed(false)
214 #endif
215 #if ENABLE(GESTURE_RECOGNIZER)
216 , m_gestureRecognizer(PlatformGestureRecognizer::create())
217 #endif
218 {
219 }
220
~EventHandler()221 EventHandler::~EventHandler()
222 {
223 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
224 }
225
226 #if ENABLE(DRAG_SUPPORT)
dragState()227 EventHandler::EventHandlerDragState& EventHandler::dragState()
228 {
229 DEFINE_STATIC_LOCAL(EventHandlerDragState, state, ());
230 return state;
231 }
232 #endif // ENABLE(DRAG_SUPPORT)
233
clear()234 void EventHandler::clear()
235 {
236 m_hoverTimer.stop();
237 m_fakeMouseMoveEventTimer.stop();
238 m_resizeLayer = 0;
239 m_nodeUnderMouse = 0;
240 m_lastNodeUnderMouse = 0;
241 #if ENABLE(SVG)
242 m_instanceUnderMouse = 0;
243 m_lastInstanceUnderMouse = 0;
244 #endif
245 m_lastMouseMoveEventSubframe = 0;
246 m_lastScrollbarUnderMouse = 0;
247 m_clickCount = 0;
248 m_clickNode = 0;
249 m_frameSetBeingResized = 0;
250 #if ENABLE(DRAG_SUPPORT)
251 m_dragTarget = 0;
252 m_shouldOnlyFireDragOverEvent = false;
253 #endif
254 m_currentMousePosition = IntPoint();
255 m_mousePressNode = 0;
256 m_mousePressed = false;
257 m_capturesDragging = false;
258 m_capturingMouseEventsNode = 0;
259 m_latchedWheelEventNode = 0;
260 m_previousWheelScrolledNode = 0;
261 #if ENABLE(TOUCH_EVENTS)
262 m_originatingTouchPointTargets.clear();
263 #if PLATFORM(ANDROID)
264 m_capturingTouchEventsNode = 0;
265 #endif
266 #endif
267 }
268
setSelectionIfNeeded(SelectionController * selection,const VisibleSelection & newSelection)269 static void setSelectionIfNeeded(SelectionController* selection, const VisibleSelection& newSelection)
270 {
271 ASSERT(selection);
272 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
273 selection->setSelection(newSelection);
274 }
275
setNonDirectionalSelectionIfNeeded(SelectionController * selection,const VisibleSelection & newSelection,TextGranularity granularity)276 static void setNonDirectionalSelectionIfNeeded(SelectionController* selection, const VisibleSelection& newSelection, TextGranularity granularity)
277 {
278 ASSERT(selection);
279 if (selection->selection() != newSelection && selection->shouldChangeSelection(newSelection))
280 selection->setSelection(newSelection, granularity, MakeNonDirectionalSelection);
281 }
282
selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults & result)283 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
284 {
285 Node* innerNode = targetNode(result);
286 VisibleSelection newSelection;
287
288 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
289 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
290 TextGranularity granularity = CharacterGranularity;
291 if (pos.isNotNull()) {
292 newSelection = VisibleSelection(pos);
293 newSelection.expandUsingGranularity(WordGranularity);
294 }
295
296 if (newSelection.isRange()) {
297 granularity = WordGranularity;
298 m_beganSelectingText = true;
299 if (result.event().clickCount() == 2 && m_frame->editor()->isSelectTrailingWhitespaceEnabled())
300 newSelection.appendTrailingWhitespace();
301 }
302
303 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
304 }
305 }
306
selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults & result)307 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
308 {
309 if (!result.hitTestResult().isLiveLink())
310 return selectClosestWordFromMouseEvent(result);
311
312 Node* innerNode = targetNode(result);
313
314 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
315 VisibleSelection newSelection;
316 Element* URLElement = result.hitTestResult().URLElement();
317 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
318 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
319 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
320
321 TextGranularity granularity = CharacterGranularity;
322 if (newSelection.isRange()) {
323 granularity = WordGranularity;
324 m_beganSelectingText = true;
325 }
326
327 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
328 }
329 }
330
handleMousePressEventDoubleClick(const MouseEventWithHitTestResults & event)331 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
332 {
333 if (event.event().button() != LeftButton)
334 return false;
335
336 if (m_frame->selection()->isRange())
337 // A double-click when range is already selected
338 // should not change the selection. So, do not call
339 // selectClosestWordFromMouseEvent, but do set
340 // m_beganSelectingText to prevent handleMouseReleaseEvent
341 // from setting caret selection.
342 m_beganSelectingText = true;
343 else
344 selectClosestWordFromMouseEvent(event);
345
346 return true;
347 }
348
handleMousePressEventTripleClick(const MouseEventWithHitTestResults & event)349 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
350 {
351 if (event.event().button() != LeftButton)
352 return false;
353
354 Node* innerNode = targetNode(event);
355 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
356 return false;
357
358 VisibleSelection newSelection;
359 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
360 if (pos.isNotNull()) {
361 newSelection = VisibleSelection(pos);
362 newSelection.expandUsingGranularity(ParagraphGranularity);
363 }
364
365 TextGranularity granularity = CharacterGranularity;
366 if (newSelection.isRange()) {
367 granularity = ParagraphGranularity;
368 m_beganSelectingText = true;
369 }
370
371 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
372
373 return true;
374 }
375
textDistance(const Position & start,const Position & end)376 static int textDistance(const Position& start, const Position& end)
377 {
378 RefPtr<Range> range = Range::create(start.anchorNode()->document(), start, end);
379 return TextIterator::rangeLength(range.get(), true);
380 }
381
handleMousePressEventSingleClick(const MouseEventWithHitTestResults & event)382 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
383 {
384 Node* innerNode = targetNode(event);
385 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
386 return false;
387
388 // Extend the selection if the Shift key is down, unless the click is in a link.
389 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
390
391 // Don't restart the selection when the mouse is pressed on an
392 // existing selection so we can allow for text dragging.
393 if (FrameView* view = m_frame->view()) {
394 IntPoint vPoint = view->windowToContents(event.event().pos());
395 if (!extendSelection && m_frame->selection()->contains(vPoint)) {
396 m_mouseDownWasSingleClickInSelection = true;
397 return false;
398 }
399 }
400
401 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
402 if (visiblePos.isNull())
403 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
404 Position pos = visiblePos.deepEquivalent();
405
406 VisibleSelection newSelection = m_frame->selection()->selection();
407 TextGranularity granularity = CharacterGranularity;
408
409 if (extendSelection && newSelection.isCaretOrRange()) {
410 m_frame->selection()->setIsDirectional(false);
411
412 ASSERT(m_frame->settings());
413 if (m_frame->settings()->editingBehaviorType() == EditingMacBehavior) {
414 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
415 // was created right-to-left
416 Position start = newSelection.start();
417 Position end = newSelection.end();
418 int distanceToStart = textDistance(start, pos);
419 int distanceToEnd = textDistance(pos, end);
420 if (distanceToStart <= distanceToEnd)
421 newSelection = VisibleSelection(end, pos);
422 else
423 newSelection = VisibleSelection(start, pos);
424 } else {
425 newSelection.setExtent(pos);
426 }
427
428 if (m_frame->selection()->granularity() != CharacterGranularity) {
429 granularity = m_frame->selection()->granularity();
430 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
431 }
432
433 m_beganSelectingText = true;
434 } else
435 newSelection = VisibleSelection(visiblePos);
436
437 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, granularity);
438
439 return true;
440 }
441
handleMousePressEvent(const MouseEventWithHitTestResults & event)442 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
443 {
444 #if ENABLE(DRAG_SUPPORT)
445 // Reset drag state.
446 dragState().m_dragSrc = 0;
447 #endif
448
449 cancelFakeMouseMoveEvent();
450
451 if (ScrollView* scrollView = m_frame->view()) {
452 if (scrollView->isPointInScrollbarCorner(event.event().pos()))
453 return false;
454 }
455
456 bool singleClick = event.event().clickCount() <= 1;
457
458 // If we got the event back, that must mean it wasn't prevented,
459 // so it's allowed to start a drag or selection.
460 m_mouseDownMayStartSelect = canMouseDownStartSelect(targetNode(event));
461
462 #if ENABLE(DRAG_SUPPORT)
463 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
464 m_mouseDownMayStartDrag = singleClick;
465 #endif
466
467 m_mouseDownWasSingleClickInSelection = false;
468
469 m_mouseDown = event.event();
470
471 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
472 return true;
473
474 #if ENABLE(SVG)
475 if (m_frame->document()->isSVGDocument()
476 && static_cast<SVGDocument*>(m_frame->document())->zoomAndPanEnabled()) {
477 if (event.event().shiftKey() && singleClick) {
478 m_svgPan = true;
479 static_cast<SVGDocument*>(m_frame->document())->startPan(event.event().pos());
480 return true;
481 }
482 }
483 #endif
484
485 // We don't do this at the start of mouse down handling,
486 // because we don't want to do it until we know we didn't hit a widget.
487 if (singleClick)
488 focusDocumentView();
489
490 Node* innerNode = targetNode(event);
491
492 m_mousePressNode = innerNode;
493 #if ENABLE(DRAG_SUPPORT)
494 m_dragStartPos = event.event().pos();
495 #endif
496
497 bool swallowEvent = false;
498 m_mousePressed = true;
499 m_beganSelectingText = false;
500
501 if (event.event().clickCount() == 2)
502 swallowEvent = handleMousePressEventDoubleClick(event);
503 else if (event.event().clickCount() >= 3)
504 swallowEvent = handleMousePressEventTripleClick(event);
505 else
506 swallowEvent = handleMousePressEventSingleClick(event);
507
508 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
509 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled(true));
510
511 return swallowEvent;
512 }
513
514 // There are two kinds of renderer that can autoscroll.
canAutoscroll(RenderObject * renderer)515 static bool canAutoscroll(RenderObject* renderer)
516 {
517 if (!renderer->isBox())
518 return false;
519
520 // Check for a box that can be scrolled in its own right.
521 if (toRenderBox(renderer)->canBeScrolledAndHasScrollableArea())
522 return true;
523
524 // Check for a box that represents the top level of a web page.
525 // This can be scrolled by calling Chrome::scrollRectIntoView.
526 // This only has an effect on the Mac platform in applications
527 // that put web views into scrolling containers, such as Mac OS X Mail.
528 // The code for this is in RenderLayer::scrollRectToVisible.
529 if (renderer->node() != renderer->document())
530 return false;
531 Frame* frame = renderer->frame();
532 if (!frame)
533 return false;
534 Page* page = frame->page();
535 return page && page->mainFrame() == frame;
536 }
537
538 #if ENABLE(DRAG_SUPPORT)
handleMouseDraggedEvent(const MouseEventWithHitTestResults & event)539 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
540 {
541 if (handleDrag(event))
542 return true;
543
544 if (!m_mousePressed)
545 return false;
546
547 Node* targetNode = EventHandler::targetNode(event);
548 if (event.event().button() != LeftButton || !targetNode || !targetNode->renderer())
549 return false;
550
551 #if PLATFORM(MAC) // FIXME: Why does this assertion fire on other platforms?
552 ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll);
553 #endif
554
555 m_mouseDownMayStartDrag = false;
556
557 if (m_mouseDownMayStartAutoscroll && !m_panScrollInProgress) {
558 // Find a renderer that can autoscroll.
559 RenderObject* renderer = targetNode->renderer();
560 while (renderer && !canAutoscroll(renderer)) {
561 if (!renderer->parent() && renderer->node() == renderer->document() && renderer->document()->ownerElement())
562 renderer = renderer->document()->ownerElement()->renderer();
563 else
564 renderer = renderer->parent();
565 }
566
567 if (renderer) {
568 m_autoscrollInProgress = true;
569 handleAutoscroll(renderer);
570 }
571
572 m_mouseDownMayStartAutoscroll = false;
573 }
574
575 if (!m_beganSelectingText) {
576 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
577 HitTestResult result(m_mouseDownPos);
578 m_frame->document()->renderView()->layer()->hitTest(request, result);
579
580 updateSelectionForMouseDrag(result);
581 }
582 updateSelectionForMouseDrag(event.hitTestResult());
583 return true;
584 }
585
eventMayStartDrag(const PlatformMouseEvent & event) const586 bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const
587 {
588 // This is a pre-flight check of whether the event might lead to a drag being started. Be careful
589 // that its logic needs to stay in sync with handleMouseMoveEvent() and the way we setMouseDownMayStartDrag
590 // in handleMousePressEvent
591
592 if (!m_frame->contentRenderer() || !m_frame->contentRenderer()->hasLayer())
593 return false;
594
595 if (event.button() != LeftButton || event.clickCount() != 1)
596 return false;
597
598 bool DHTMLFlag;
599 bool UAFlag;
600 allowDHTMLDrag(DHTMLFlag, UAFlag);
601 if (!DHTMLFlag && !UAFlag)
602 return false;
603
604 FrameView* view = m_frame->view();
605 if (!view)
606 return false;
607
608 HitTestRequest request(HitTestRequest::ReadOnly);
609 HitTestResult result(view->windowToContents(event.pos()));
610 m_frame->contentRenderer()->layer()->hitTest(request, result);
611 bool srcIsDHTML;
612 return result.innerNode() && result.innerNode()->renderer()->draggableNode(DHTMLFlag, UAFlag, result.point().x(), result.point().y(), srcIsDHTML);
613 }
614
updateSelectionForMouseDrag()615 void EventHandler::updateSelectionForMouseDrag()
616 {
617 FrameView* view = m_frame->view();
618 if (!view)
619 return;
620 RenderView* renderer = m_frame->contentRenderer();
621 if (!renderer)
622 return;
623 RenderLayer* layer = renderer->layer();
624 if (!layer)
625 return;
626
627 HitTestRequest request(HitTestRequest::ReadOnly |
628 HitTestRequest::Active |
629 HitTestRequest::MouseMove);
630 HitTestResult result(view->windowToContents(m_currentMousePosition));
631 layer->hitTest(request, result);
632 updateSelectionForMouseDrag(result);
633 }
634
selectionExtentRespectingEditingBoundary(const VisibleSelection & selection,const IntPoint & localPoint,Node * targetNode)635 static VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection& selection, const IntPoint& localPoint, Node* targetNode)
636 {
637 IntPoint selectionEndPoint = localPoint;
638 Element* editableElement = selection.rootEditableElement();
639
640 if (!targetNode->renderer())
641 return VisiblePosition();
642
643 if (editableElement && !editableElement->contains(targetNode)) {
644 if (!editableElement->renderer())
645 return VisiblePosition();
646
647 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
648 selectionEndPoint = roundedIntPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
649 targetNode = editableElement;
650 }
651
652 return targetNode->renderer()->positionForPoint(selectionEndPoint);
653 }
654
updateSelectionForMouseDrag(const HitTestResult & hitTestResult)655 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
656 {
657 if (!m_mouseDownMayStartSelect)
658 return;
659
660 Node* target = targetNode(hitTestResult);
661 if (!target)
662 return;
663
664 if (!canMouseDragExtendSelect(target))
665 return;
666
667 VisiblePosition targetPosition = selectionExtentRespectingEditingBoundary(m_frame->selection()->selection(), hitTestResult.localPoint(), target);
668
669 // Don't modify the selection if we're not on a node.
670 if (targetPosition.isNull())
671 return;
672
673 // Restart the selection if this is the first mouse move. This work is usually
674 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
675 VisibleSelection newSelection = m_frame->selection()->selection();
676
677 #if ENABLE(SVG)
678 // Special case to limit selection to the containing block for SVG text.
679 // FIXME: Isn't there a better non-SVG-specific way to do this?
680 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
681 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
682 if (selectionBaseRenderer->isSVGText())
683 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
684 return;
685 #endif
686
687 if (!m_beganSelectingText) {
688 m_beganSelectingText = true;
689 newSelection = VisibleSelection(targetPosition);
690 }
691
692 newSelection.setExtent(targetPosition);
693 if (m_frame->selection()->granularity() != CharacterGranularity)
694 newSelection.expandUsingGranularity(m_frame->selection()->granularity());
695
696 setNonDirectionalSelectionIfNeeded(m_frame->selection(), newSelection, m_frame->selection()->granularity());
697 }
698 #endif // ENABLE(DRAG_SUPPORT)
699
lostMouseCapture()700 void EventHandler::lostMouseCapture()
701 {
702 m_frame->selection()->setCaretBlinkingSuspended(false);
703 }
704
handleMouseUp(const MouseEventWithHitTestResults & event)705 bool EventHandler::handleMouseUp(const MouseEventWithHitTestResults& event)
706 {
707 if (eventLoopHandleMouseUp(event))
708 return true;
709
710 // If this was the first click in the window, we don't even want to clear the selection.
711 // This case occurs when the user clicks on a draggable element, since we have to process
712 // the mouse down and drag events to see if we might start a drag. For other first clicks
713 // in a window, we just don't acceptFirstMouse, and the whole down-drag-up sequence gets
714 // ignored upstream of this layer.
715 return eventActivatedView(event.event());
716 }
717
handleMouseReleaseEvent(const MouseEventWithHitTestResults & event)718 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
719 {
720 if (m_autoscrollInProgress)
721 stopAutoscrollTimer();
722
723 if (handleMouseUp(event))
724 return true;
725
726 // Used to prevent mouseMoveEvent from initiating a drag before
727 // the mouse is pressed again.
728 m_frame->selection()->setCaretBlinkingSuspended(false);
729 m_mousePressed = false;
730 m_capturesDragging = false;
731 #if ENABLE(DRAG_SUPPORT)
732 m_mouseDownMayStartDrag = false;
733 #endif
734 m_mouseDownMayStartSelect = false;
735 m_mouseDownMayStartAutoscroll = false;
736 m_mouseDownWasInSubframe = false;
737
738 bool handled = false;
739
740 // Clear the selection if the mouse didn't move after the last mouse
741 // press and it's not a context menu click. We do this so when clicking
742 // on the selection, the selection goes away. However, if we are
743 // editing, place the caret.
744 if (m_mouseDownWasSingleClickInSelection && !m_beganSelectingText
745 #if ENABLE(DRAG_SUPPORT)
746 && m_dragStartPos == event.event().pos()
747 #endif
748 && m_frame->selection()->isRange()
749 && event.event().button() != RightButton) {
750 VisibleSelection newSelection;
751 Node* node = targetNode(event);
752 bool caretBrowsing = m_frame->settings()->caretBrowsingEnabled();
753 if (node && (caretBrowsing || node->rendererIsEditable()) && node->renderer()) {
754 VisiblePosition pos = node->renderer()->positionForPoint(event.localPoint());
755 newSelection = VisibleSelection(pos);
756 }
757
758 setSelectionIfNeeded(m_frame->selection(), newSelection);
759
760 handled = true;
761 }
762
763 m_frame->selection()->notifyRendererOfSelectionChange(true);
764
765 m_frame->selection()->selectFrameElementInParentIfFullySelected();
766
767 return handled;
768 }
769
handleAutoscroll(RenderObject * renderer)770 void EventHandler::handleAutoscroll(RenderObject* renderer)
771 {
772 // We don't want to trigger the autoscroll or the panScroll if it's already active
773 if (m_autoscrollTimer.isActive())
774 return;
775
776 setAutoscrollRenderer(renderer);
777
778 #if ENABLE(PAN_SCROLLING)
779 if (m_panScrollInProgress) {
780 m_panScrollStartPos = currentMousePosition();
781 if (FrameView* view = m_frame->view())
782 view->addPanScrollIcon(m_panScrollStartPos);
783 // If we're not in the top frame we notify it that we doing a panScroll.
784 if (Page* page = m_frame->page()) {
785 Frame* mainFrame = page->mainFrame();
786 if (m_frame != mainFrame)
787 mainFrame->eventHandler()->setPanScrollInProgress(true);
788 }
789 }
790 #endif
791
792 startAutoscrollTimer();
793 }
794
autoscrollTimerFired(Timer<EventHandler> *)795 void EventHandler::autoscrollTimerFired(Timer<EventHandler>*)
796 {
797 RenderObject* r = autoscrollRenderer();
798 if (!r || !r->isBox()) {
799 stopAutoscrollTimer();
800 return;
801 }
802
803 if (m_autoscrollInProgress) {
804 if (!m_mousePressed) {
805 stopAutoscrollTimer();
806 return;
807 }
808 toRenderBox(r)->autoscroll();
809 } else {
810 // we verify that the main frame hasn't received the order to stop the panScroll
811 if (Page* page = m_frame->page()) {
812 if (!page->mainFrame()->eventHandler()->panScrollInProgress()) {
813 stopAutoscrollTimer();
814 return;
815 }
816 }
817 #if ENABLE(PAN_SCROLLING)
818 updatePanScrollState();
819 toRenderBox(r)->panScroll(m_panScrollStartPos);
820 #endif
821 }
822 }
823
824 #if ENABLE(PAN_SCROLLING)
825
startPanScrolling(RenderObject * renderer)826 void EventHandler::startPanScrolling(RenderObject* renderer)
827 {
828 m_panScrollInProgress = true;
829 m_panScrollButtonPressed = true;
830 handleAutoscroll(renderer);
831 invalidateClick();
832 }
833
updatePanScrollState()834 void EventHandler::updatePanScrollState()
835 {
836 FrameView* view = m_frame->view();
837 if (!view)
838 return;
839
840 // At the original click location we draw a 4 arrowed icon. Over this icon there won't be any scroll
841 // So we don't want to change the cursor over this area
842 bool east = m_panScrollStartPos.x() < (m_currentMousePosition.x() - ScrollView::noPanScrollRadius);
843 bool west = m_panScrollStartPos.x() > (m_currentMousePosition.x() + ScrollView::noPanScrollRadius);
844 bool north = m_panScrollStartPos.y() > (m_currentMousePosition.y() + ScrollView::noPanScrollRadius);
845 bool south = m_panScrollStartPos.y() < (m_currentMousePosition.y() - ScrollView::noPanScrollRadius);
846
847 if ((east || west || north || south) && m_panScrollButtonPressed)
848 m_springLoadedPanScrollInProgress = true;
849
850 if (north) {
851 if (east)
852 view->setCursor(northEastPanningCursor());
853 else if (west)
854 view->setCursor(northWestPanningCursor());
855 else
856 view->setCursor(northPanningCursor());
857 } else if (south) {
858 if (east)
859 view->setCursor(southEastPanningCursor());
860 else if (west)
861 view->setCursor(southWestPanningCursor());
862 else
863 view->setCursor(southPanningCursor());
864 } else if (east)
865 view->setCursor(eastPanningCursor());
866 else if (west)
867 view->setCursor(westPanningCursor());
868 else
869 view->setCursor(middlePanningCursor());
870 }
871
872 #endif // ENABLE(PAN_SCROLLING)
873
autoscrollRenderer() const874 RenderObject* EventHandler::autoscrollRenderer() const
875 {
876 return m_autoscrollRenderer;
877 }
878
updateAutoscrollRenderer()879 void EventHandler::updateAutoscrollRenderer()
880 {
881 if (!m_autoscrollRenderer)
882 return;
883
884 HitTestResult hitTest = hitTestResultAtPoint(m_panScrollStartPos, true);
885
886 if (Node* nodeAtPoint = hitTest.innerNode())
887 m_autoscrollRenderer = nodeAtPoint->renderer();
888
889 while (m_autoscrollRenderer && !canAutoscroll(m_autoscrollRenderer))
890 m_autoscrollRenderer = m_autoscrollRenderer->parent();
891 }
892
setAutoscrollRenderer(RenderObject * renderer)893 void EventHandler::setAutoscrollRenderer(RenderObject* renderer)
894 {
895 m_autoscrollRenderer = renderer;
896 }
897
898 #if ENABLE(DRAG_SUPPORT)
allowDHTMLDrag(bool & flagDHTML,bool & flagUA) const899 void EventHandler::allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const
900 {
901 flagDHTML = false;
902 flagUA = false;
903
904 if (!m_frame)
905 return;
906
907 Page* page = m_frame->page();
908 if (!page)
909 return;
910
911 FrameView* view = m_frame->view();
912 if (!view)
913 return;
914
915 unsigned mask = page->dragController()->delegateDragSourceAction(view->contentsToWindow(m_mouseDownPos));
916 flagDHTML = (mask & DragSourceActionDHTML) != DragSourceActionNone;
917 flagUA = ((mask & DragSourceActionImage) || (mask & DragSourceActionLink) || (mask & DragSourceActionSelection));
918 }
919 #endif // ENABLE(DRAG_SUPPORT)
920
hitTestResultAtPoint(const IntPoint & point,bool allowShadowContent,bool ignoreClipping,HitTestScrollbars testScrollbars,HitTestRequest::HitTestRequestType hitType,const IntSize & padding)921 HitTestResult EventHandler::hitTestResultAtPoint(const IntPoint& point, bool allowShadowContent, bool ignoreClipping, HitTestScrollbars testScrollbars, HitTestRequest::HitTestRequestType hitType, const IntSize& padding)
922 {
923 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
924 if (!m_frame->contentRenderer())
925 return result;
926 if (ignoreClipping)
927 hitType |= HitTestRequest::IgnoreClipping;
928 m_frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), result);
929
930 while (true) {
931 Node* n = result.innerNode();
932 if (!result.isOverWidget() || !n || !n->renderer() || !n->renderer()->isWidget())
933 break;
934 RenderWidget* renderWidget = toRenderWidget(n->renderer());
935 Widget* widget = renderWidget->widget();
936 if (!widget || !widget->isFrameView())
937 break;
938 Frame* frame = static_cast<HTMLFrameElementBase*>(n)->contentFrame();
939 if (!frame || !frame->contentRenderer())
940 break;
941 FrameView* view = static_cast<FrameView*>(widget);
942 IntPoint widgetPoint(result.localPoint().x() + view->scrollX() - renderWidget->borderLeft() - renderWidget->paddingLeft(),
943 result.localPoint().y() + view->scrollY() - renderWidget->borderTop() - renderWidget->paddingTop());
944 HitTestResult widgetHitTestResult(widgetPoint, padding.height(), padding.width(), padding.height(), padding.width());
945 frame->contentRenderer()->layer()->hitTest(HitTestRequest(hitType), widgetHitTestResult);
946 result = widgetHitTestResult;
947
948 if (testScrollbars == ShouldHitTestScrollbars) {
949 Scrollbar* eventScrollbar = view->scrollbarAtPoint(point);
950 if (eventScrollbar)
951 result.setScrollbar(eventScrollbar);
952 }
953 }
954
955 // If our HitTestResult is not visible, then we started hit testing too far down the frame chain.
956 // Another hit test at the main frame level should get us the correct visible result.
957 Frame* resultFrame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : 0;
958 if (Page* page = m_frame->page()) {
959 Frame* mainFrame = page->mainFrame();
960 if (m_frame != mainFrame && resultFrame && resultFrame != mainFrame && !resultFrame->editor()->insideVisibleArea(result.point())) {
961 FrameView* resultView = resultFrame->view();
962 FrameView* mainView = mainFrame->view();
963 if (resultView && mainView) {
964 IntPoint windowPoint = resultView->contentsToWindow(result.point());
965 IntPoint mainFramePoint = mainView->windowToContents(windowPoint);
966 result = mainFrame->eventHandler()->hitTestResultAtPoint(mainFramePoint, allowShadowContent, ignoreClipping, testScrollbars, hitType, padding);
967 }
968 }
969 }
970
971 if (!allowShadowContent)
972 result.setToNonShadowAncestor();
973
974 return result;
975 }
976
977
startAutoscrollTimer()978 void EventHandler::startAutoscrollTimer()
979 {
980 m_autoscrollTimer.startRepeating(autoscrollInterval);
981 }
982
stopAutoscrollTimer(bool rendererIsBeingDestroyed)983 void EventHandler::stopAutoscrollTimer(bool rendererIsBeingDestroyed)
984 {
985 if (m_autoscrollInProgress) {
986 if (m_mouseDownWasInSubframe) {
987 if (Frame* subframe = subframeForTargetNode(m_mousePressNode.get()))
988 subframe->eventHandler()->stopAutoscrollTimer(rendererIsBeingDestroyed);
989 return;
990 }
991 }
992
993 if (autoscrollRenderer()) {
994 if (!rendererIsBeingDestroyed && (m_autoscrollInProgress || m_panScrollInProgress))
995 toRenderBox(autoscrollRenderer())->stopAutoscroll();
996 #if ENABLE(PAN_SCROLLING)
997 if (m_panScrollInProgress) {
998 if (FrameView* view = m_frame->view()) {
999 view->removePanScrollIcon();
1000 view->setCursor(pointerCursor());
1001 }
1002 }
1003 #endif
1004
1005 setAutoscrollRenderer(0);
1006 }
1007
1008 m_autoscrollTimer.stop();
1009
1010 m_panScrollInProgress = false;
1011 m_springLoadedPanScrollInProgress = false;
1012
1013 // If we're not in the top frame we notify it that we are not doing a panScroll any more.
1014 if (Page* page = m_frame->page()) {
1015 Frame* mainFrame = page->mainFrame();
1016 if (m_frame != mainFrame)
1017 mainFrame->eventHandler()->setPanScrollInProgress(false);
1018 }
1019
1020 m_autoscrollInProgress = false;
1021 }
1022
mousePressNode() const1023 Node* EventHandler::mousePressNode() const
1024 {
1025 return m_mousePressNode.get();
1026 }
1027
setMousePressNode(PassRefPtr<Node> node)1028 void EventHandler::setMousePressNode(PassRefPtr<Node> node)
1029 {
1030 m_mousePressNode = node;
1031 }
1032
scrollOverflow(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)1033 bool EventHandler::scrollOverflow(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1034 {
1035 Node* node = startingNode;
1036
1037 if (!node)
1038 node = m_frame->document()->focusedNode();
1039
1040 if (!node)
1041 node = m_mousePressNode.get();
1042
1043 if (node) {
1044 RenderObject* r = node->renderer();
1045 if (r && !r->isListBox() && r->enclosingBox()->scroll(direction, granularity)) {
1046 setFrameWasScrolledByUser();
1047 return true;
1048 }
1049 }
1050
1051 return false;
1052 }
1053
logicalScrollOverflow(ScrollLogicalDirection direction,ScrollGranularity granularity,Node * startingNode)1054 bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1055 {
1056 Node* node = startingNode;
1057
1058 if (!node)
1059 node = m_frame->document()->focusedNode();
1060
1061 if (!node)
1062 node = m_mousePressNode.get();
1063
1064 if (node) {
1065 RenderObject* r = node->renderer();
1066 if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
1067 setFrameWasScrolledByUser();
1068 return true;
1069 }
1070 }
1071
1072 return false;
1073 }
1074
scrollRecursively(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)1075 bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
1076 {
1077 // The layout needs to be up to date to determine if we can scroll. We may be
1078 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1079 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1080 if (scrollOverflow(direction, granularity, startingNode))
1081 return true;
1082 Frame* frame = m_frame;
1083 FrameView* view = frame->view();
1084 if (view && view->scroll(direction, granularity))
1085 return true;
1086 frame = frame->tree()->parent();
1087 if (!frame)
1088 return false;
1089 return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->ownerElement());
1090 }
1091
logicalScrollRecursively(ScrollLogicalDirection direction,ScrollGranularity granularity,Node * startingNode)1092 bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
1093 {
1094 // The layout needs to be up to date to determine if we can scroll. We may be
1095 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
1096 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1097 if (logicalScrollOverflow(direction, granularity, startingNode))
1098 return true;
1099 Frame* frame = m_frame;
1100 FrameView* view = frame->view();
1101
1102 bool scrolled = false;
1103 #if PLATFORM(MAC)
1104 // Mac also resets the scroll position in the inline direction.
1105 if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
1106 scrolled = true;
1107 #endif
1108 if (view && view->logicalScroll(direction, granularity))
1109 scrolled = true;
1110
1111 if (scrolled)
1112 return true;
1113
1114 frame = frame->tree()->parent();
1115 if (!frame)
1116 return false;
1117
1118 return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->ownerElement());
1119 }
1120
currentMousePosition() const1121 IntPoint EventHandler::currentMousePosition() const
1122 {
1123 return m_currentMousePosition;
1124 }
1125
subframeForHitTestResult(const MouseEventWithHitTestResults & hitTestResult)1126 Frame* EventHandler::subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
1127 {
1128 if (!hitTestResult.isOverWidget())
1129 return 0;
1130 return subframeForTargetNode(targetNode(hitTestResult));
1131 }
1132
subframeForTargetNode(Node * node)1133 Frame* EventHandler::subframeForTargetNode(Node* node)
1134 {
1135 if (!node)
1136 return 0;
1137
1138 RenderObject* renderer = node->renderer();
1139 if (!renderer || !renderer->isWidget())
1140 return 0;
1141
1142 Widget* widget = toRenderWidget(renderer)->widget();
1143 if (!widget || !widget->isFrameView())
1144 return 0;
1145
1146 return static_cast<FrameView*>(widget)->frame();
1147 }
1148
isSubmitImage(Node * node)1149 static bool isSubmitImage(Node* node)
1150 {
1151 return node && node->hasTagName(inputTag) && static_cast<HTMLInputElement*>(node)->isImageButton();
1152 }
1153
1154 // Returns true if the node's editable block is not current focused for editing
nodeIsNotBeingEdited(Node * node,Frame * frame)1155 static bool nodeIsNotBeingEdited(Node* node, Frame* frame)
1156 {
1157 return frame->selection()->rootEditableElement() != node->rootEditableElement();
1158 }
1159
selectCursor(const MouseEventWithHitTestResults & event,Scrollbar * scrollbar)1160 Cursor EventHandler::selectCursor(const MouseEventWithHitTestResults& event, Scrollbar* scrollbar)
1161 {
1162 Node* node = targetNode(event);
1163 RenderObject* renderer = node ? node->renderer() : 0;
1164 RenderStyle* style = renderer ? renderer->style() : 0;
1165
1166 bool horizontalText = !style || style->isHorizontalWritingMode();
1167 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1168
1169 // During selection, use an I-beam no matter what we're over.
1170 // If you're capturing mouse events for a particular node, don't treat this as a selection.
1171 if (m_mousePressed && m_mouseDownMayStartSelect && m_frame->selection()->isCaretOrRange() && !m_capturingMouseEventsNode)
1172 return iBeam;
1173
1174 if (renderer && renderer->isFrameSet()) {
1175 RenderFrameSet* frameSetRenderer = toRenderFrameSet(renderer);
1176 if (frameSetRenderer->canResizeRow(event.localPoint()))
1177 return rowResizeCursor();
1178 if (frameSetRenderer->canResizeColumn(event.localPoint()))
1179 return columnResizeCursor();
1180 }
1181
1182 if (style && style->cursors()) {
1183 const CursorList* cursors = style->cursors();
1184 for (unsigned i = 0; i < cursors->size(); ++i) {
1185 const CachedImage* cimage = 0;
1186 StyleImage* image = (*cursors)[i].image();
1187 if (image && image->isCachedImage())
1188 cimage = static_cast<StyleCachedImage*>(image)->cachedImage();
1189 if (!cimage)
1190 continue;
1191 IntPoint hotSpot = (*cursors)[i].hotSpot();
1192 // Limit the size of cursors so that they cannot be used to cover UI elements in chrome.
1193 IntSize size = cimage->image()->size();
1194 if (size.width() > 128 || size.height() > 128)
1195 continue;
1196 if (cimage->image()->isNull())
1197 break;
1198 if (!cimage->errorOccurred())
1199 return Cursor(cimage->image(), hotSpot);
1200 }
1201 }
1202
1203 switch (style ? style->cursor() : CURSOR_AUTO) {
1204 case CURSOR_AUTO: {
1205 bool editable = (node && node->rendererIsEditable());
1206 bool editableLinkEnabled = false;
1207
1208 // If the link is editable, then we need to check the settings to see whether or not the link should be followed
1209 if (editable) {
1210 ASSERT(m_frame->settings());
1211 switch (m_frame->settings()->editableLinkBehavior()) {
1212 default:
1213 case EditableLinkDefaultBehavior:
1214 case EditableLinkAlwaysLive:
1215 editableLinkEnabled = true;
1216 break;
1217
1218 case EditableLinkNeverLive:
1219 editableLinkEnabled = false;
1220 break;
1221
1222 case EditableLinkLiveWhenNotFocused:
1223 editableLinkEnabled = nodeIsNotBeingEdited(node, m_frame) || event.event().shiftKey();
1224 break;
1225
1226 case EditableLinkOnlyLiveWithShiftKey:
1227 editableLinkEnabled = event.event().shiftKey();
1228 break;
1229 }
1230 }
1231
1232 if ((event.isOverLink() || isSubmitImage(node)) && (!editable || editableLinkEnabled))
1233 return handCursor();
1234 bool inResizer = false;
1235 if (renderer) {
1236 if (RenderLayer* layer = renderer->enclosingLayer()) {
1237 if (FrameView* view = m_frame->view())
1238 inResizer = layer->isPointInResizeControl(view->windowToContents(event.event().pos()));
1239 }
1240 }
1241 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !scrollbar)
1242 return iBeam;
1243 return pointerCursor();
1244 }
1245 case CURSOR_CROSS:
1246 return crossCursor();
1247 case CURSOR_POINTER:
1248 return handCursor();
1249 case CURSOR_MOVE:
1250 return moveCursor();
1251 case CURSOR_ALL_SCROLL:
1252 return moveCursor();
1253 case CURSOR_E_RESIZE:
1254 return eastResizeCursor();
1255 case CURSOR_W_RESIZE:
1256 return westResizeCursor();
1257 case CURSOR_N_RESIZE:
1258 return northResizeCursor();
1259 case CURSOR_S_RESIZE:
1260 return southResizeCursor();
1261 case CURSOR_NE_RESIZE:
1262 return northEastResizeCursor();
1263 case CURSOR_SW_RESIZE:
1264 return southWestResizeCursor();
1265 case CURSOR_NW_RESIZE:
1266 return northWestResizeCursor();
1267 case CURSOR_SE_RESIZE:
1268 return southEastResizeCursor();
1269 case CURSOR_NS_RESIZE:
1270 return northSouthResizeCursor();
1271 case CURSOR_EW_RESIZE:
1272 return eastWestResizeCursor();
1273 case CURSOR_NESW_RESIZE:
1274 return northEastSouthWestResizeCursor();
1275 case CURSOR_NWSE_RESIZE:
1276 return northWestSouthEastResizeCursor();
1277 case CURSOR_COL_RESIZE:
1278 return columnResizeCursor();
1279 case CURSOR_ROW_RESIZE:
1280 return rowResizeCursor();
1281 case CURSOR_TEXT:
1282 return iBeamCursor();
1283 case CURSOR_WAIT:
1284 return waitCursor();
1285 case CURSOR_HELP:
1286 return helpCursor();
1287 case CURSOR_VERTICAL_TEXT:
1288 return verticalTextCursor();
1289 case CURSOR_CELL:
1290 return cellCursor();
1291 case CURSOR_CONTEXT_MENU:
1292 return contextMenuCursor();
1293 case CURSOR_PROGRESS:
1294 return progressCursor();
1295 case CURSOR_NO_DROP:
1296 return noDropCursor();
1297 case CURSOR_ALIAS:
1298 return aliasCursor();
1299 case CURSOR_COPY:
1300 return copyCursor();
1301 case CURSOR_NONE:
1302 return noneCursor();
1303 case CURSOR_NOT_ALLOWED:
1304 return notAllowedCursor();
1305 case CURSOR_DEFAULT:
1306 return pointerCursor();
1307 case CURSOR_WEBKIT_ZOOM_IN:
1308 return zoomInCursor();
1309 case CURSOR_WEBKIT_ZOOM_OUT:
1310 return zoomOutCursor();
1311 case CURSOR_WEBKIT_GRAB:
1312 return grabCursor();
1313 case CURSOR_WEBKIT_GRABBING:
1314 return grabbingCursor();
1315 }
1316 return pointerCursor();
1317 }
1318
documentPointForWindowPoint(Frame * frame,const IntPoint & windowPoint)1319 static IntPoint documentPointForWindowPoint(Frame* frame, const IntPoint& windowPoint)
1320 {
1321 FrameView* view = frame->view();
1322 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1323 // Historically the code would just crash; this is clearly no worse than that.
1324 return view ? view->windowToContents(windowPoint) : windowPoint;
1325 }
1326
targetNode(const MouseEventWithHitTestResults & event)1327 Node* EventHandler::targetNode(const MouseEventWithHitTestResults& event)
1328 {
1329 return targetNode(event.hitTestResult());
1330 }
1331
targetNode(const HitTestResult & hitTestResult)1332 Node* EventHandler::targetNode(const HitTestResult& hitTestResult)
1333 {
1334 Node* node = hitTestResult.innerNode();
1335 if (!node)
1336 return 0;
1337 if (node->inDocument())
1338 return node;
1339
1340 Element* element = node->parentElement();
1341 if (element && element->inDocument())
1342 return element;
1343
1344 return node;
1345
1346 }
1347
handleMousePressEvent(const PlatformMouseEvent & mouseEvent)1348 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1349 {
1350 RefPtr<FrameView> protector(m_frame->view());
1351
1352 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1353
1354 cancelFakeMouseMoveEvent();
1355 m_mousePressed = true;
1356 m_capturesDragging = true;
1357 m_currentMousePosition = mouseEvent.pos();
1358 m_mouseDownTimestamp = mouseEvent.timestamp();
1359 #if ENABLE(DRAG_SUPPORT)
1360 m_mouseDownMayStartDrag = false;
1361 #endif
1362 m_mouseDownMayStartSelect = false;
1363 m_mouseDownMayStartAutoscroll = false;
1364 if (FrameView* view = m_frame->view())
1365 m_mouseDownPos = view->windowToContents(mouseEvent.pos());
1366 else {
1367 invalidateClick();
1368 return false;
1369 }
1370 m_mouseDownWasInSubframe = false;
1371
1372 #if ENABLE(COMPOSITED_FIXED_ELEMENTS)
1373 // Add IgnoreClipping because fixed position elements are moved only on the
1374 // UI thread. Nodes in fixed position elements are clipped out by the view
1375 // without IgnoreClipping.
1376 HitTestRequest request(HitTestRequest::Active | HitTestRequest::IgnoreClipping);
1377 #else
1378 HitTestRequest request(HitTestRequest::Active);
1379 #endif
1380 // Save the document point we generate in case the window coordinate is invalidated by what happens
1381 // when we dispatch the event.
1382 IntPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.pos());
1383 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1384
1385 if (!targetNode(mev)) {
1386 invalidateClick();
1387 return false;
1388 }
1389
1390 m_mousePressNode = targetNode(mev);
1391
1392 if (InspectorInstrumentation::handleMousePress(m_frame->page())) {
1393 invalidateClick();
1394 return true;
1395 }
1396
1397 Frame* subframe = subframeForHitTestResult(mev);
1398 if (subframe && passMousePressEventToSubframe(mev, subframe)) {
1399 // Start capturing future events for this frame. We only do this if we didn't clear
1400 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1401 m_capturesDragging = subframe->eventHandler()->capturesDragging();
1402 if (m_mousePressed && m_capturesDragging) {
1403 m_capturingMouseEventsNode = targetNode(mev);
1404 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1405 }
1406 invalidateClick();
1407 return true;
1408 }
1409
1410 #if ENABLE(PAN_SCROLLING)
1411 // We store whether pan scrolling is in progress before calling stopAutoscrollTimer()
1412 // because it will set m_panScrollInProgress to false on return.
1413 bool isPanScrollInProgress = m_frame->page() && m_frame->page()->mainFrame()->eventHandler()->panScrollInProgress();
1414 if (isPanScrollInProgress || m_autoscrollInProgress)
1415 stopAutoscrollTimer();
1416 if (isPanScrollInProgress) {
1417 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1418 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1419 invalidateClick();
1420 return true;
1421 }
1422 #endif
1423
1424 m_clickCount = mouseEvent.clickCount();
1425 m_clickNode = targetNode(mev);
1426
1427 if (FrameView* view = m_frame->view()) {
1428 RenderLayer* layer = m_clickNode->renderer() ? m_clickNode->renderer()->enclosingLayer() : 0;
1429 IntPoint p = view->windowToContents(mouseEvent.pos());
1430 if (layer && layer->isPointInResizeControl(p)) {
1431 layer->setInResizeMode(true);
1432 m_resizeLayer = layer;
1433 m_offsetFromResizeCorner = layer->offsetFromResizeCorner(p);
1434 invalidateClick();
1435 return true;
1436 }
1437 }
1438
1439 m_frame->selection()->setCaretBlinkingSuspended(true);
1440
1441 bool swallowEvent = dispatchMouseEvent(eventNames().mousedownEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1442 m_capturesDragging = !swallowEvent;
1443
1444 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1445 // in case the scrollbar widget was destroyed when the mouse event was handled.
1446 if (mev.scrollbar()) {
1447 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1448 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1449 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1450 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1451 m_lastScrollbarUnderMouse = 0;
1452 }
1453
1454 if (swallowEvent) {
1455 // scrollbars should get events anyway, even disabled controls might be scrollable
1456 Scrollbar* scrollbar = mev.scrollbar();
1457
1458 updateLastScrollbarUnderMouse(scrollbar, true);
1459
1460 if (scrollbar)
1461 passMousePressEventToScrollbar(mev, scrollbar);
1462 } else {
1463 // Refetch the event target node if it currently is the shadow node inside an <input> element.
1464 // If a mouse event handler changes the input element type to one that has a widget associated,
1465 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
1466 // event target node can't still be the shadow node.
1467 if (targetNode(mev)->isShadowRoot() && targetNode(mev)->shadowHost()->hasTagName(inputTag)) {
1468 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
1469 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1470 }
1471
1472 FrameView* view = m_frame->view();
1473 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mouseEvent.pos()) : 0;
1474 if (!scrollbar)
1475 scrollbar = mev.scrollbar();
1476
1477 updateLastScrollbarUnderMouse(scrollbar, true);
1478
1479 if (scrollbar && passMousePressEventToScrollbar(mev, scrollbar))
1480 swallowEvent = true;
1481 else
1482 swallowEvent = handleMousePressEvent(mev);
1483 }
1484
1485 return swallowEvent;
1486 }
1487
1488 // This method only exists for platforms that don't know how to deliver
handleMouseDoubleClickEvent(const PlatformMouseEvent & mouseEvent)1489 bool EventHandler::handleMouseDoubleClickEvent(const PlatformMouseEvent& mouseEvent)
1490 {
1491 RefPtr<FrameView> protector(m_frame->view());
1492
1493 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1494
1495 // We get this instead of a second mouse-up
1496 m_mousePressed = false;
1497 m_currentMousePosition = mouseEvent.pos();
1498
1499 HitTestRequest request(HitTestRequest::Active);
1500 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1501 Frame* subframe = subframeForHitTestResult(mev);
1502 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1503 m_capturingMouseEventsNode = 0;
1504 if (subframe && passMousePressEventToSubframe(mev, subframe))
1505 return true;
1506
1507 m_clickCount = mouseEvent.clickCount();
1508 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1509
1510 bool swallowClickEvent = mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1511
1512 if (m_lastScrollbarUnderMouse)
1513 swallowMouseUpEvent = m_lastScrollbarUnderMouse->mouseUp();
1514
1515 bool swallowMouseReleaseEvent = !swallowMouseUpEvent && handleMouseReleaseEvent(mev);
1516
1517 invalidateClick();
1518
1519 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1520 }
1521
layerForNode(Node * node)1522 static RenderLayer* layerForNode(Node* node)
1523 {
1524 if (!node)
1525 return 0;
1526
1527 RenderObject* renderer = node->renderer();
1528 if (!renderer)
1529 return 0;
1530
1531 RenderLayer* layer = renderer->enclosingLayer();
1532 if (!layer)
1533 return 0;
1534
1535 return layer;
1536 }
1537
mouseMoved(const PlatformMouseEvent & event)1538 bool EventHandler::mouseMoved(const PlatformMouseEvent& event)
1539 {
1540 HitTestResult hoveredNode = HitTestResult(IntPoint());
1541 bool result = handleMouseMoveEvent(event, &hoveredNode);
1542
1543 Page* page = m_frame->page();
1544 if (!page)
1545 return result;
1546
1547 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1548 if (page->containsScrollableArea(layer))
1549 layer->scrollAnimator()->mouseMovedInContentArea();
1550 }
1551
1552 if (FrameView* frameView = m_frame->view())
1553 frameView->scrollAnimator()->mouseMovedInContentArea();
1554
1555 hoveredNode.setToNonShadowAncestor();
1556 page->chrome()->mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1557 page->chrome()->setToolTip(hoveredNode);
1558 return result;
1559 }
1560
handleMouseMoveEvent(const PlatformMouseEvent & mouseEvent,HitTestResult * hoveredNode)1561 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode)
1562 {
1563 // in Radar 3703768 we saw frequent crashes apparently due to the
1564 // part being null here, which seems impossible, so check for nil
1565 // but also assert so that we can try to figure this out in debug
1566 // builds, if it happens.
1567 ASSERT(m_frame);
1568 if (!m_frame)
1569 return false;
1570
1571 RefPtr<FrameView> protector(m_frame->view());
1572 m_currentMousePosition = mouseEvent.pos();
1573
1574 if (m_hoverTimer.isActive())
1575 m_hoverTimer.stop();
1576
1577 cancelFakeMouseMoveEvent();
1578
1579 #if ENABLE(SVG)
1580 if (m_svgPan) {
1581 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1582 return true;
1583 }
1584 #endif
1585
1586 if (m_frameSetBeingResized)
1587 return dispatchMouseEvent(eventNames().mousemoveEvent, m_frameSetBeingResized.get(), false, 0, mouseEvent, false);
1588
1589 // Send events right to a scrollbar if the mouse is pressed.
1590 if (m_lastScrollbarUnderMouse && m_mousePressed)
1591 return m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1592
1593 // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent
1594 // if we are allowed to select.
1595 // This means that :hover and :active freeze in the state they were in when the mouse
1596 // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
1597 HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove;
1598 if (m_mousePressed && m_mouseDownMayStartSelect)
1599 hitType |= HitTestRequest::ReadOnly;
1600 if (m_mousePressed)
1601 hitType |= HitTestRequest::Active;
1602
1603 #if ENABLE(TOUCH_EVENTS)
1604 // Treat any mouse move events as readonly if the user is currently touching the screen.
1605 if (m_touchPressed)
1606 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1607 #endif
1608 HitTestRequest request(hitType);
1609 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1610 if (hoveredNode)
1611 *hoveredNode = mev.hitTestResult();
1612
1613 Scrollbar* scrollbar = 0;
1614
1615 if (m_resizeLayer && m_resizeLayer->inResizeMode())
1616 m_resizeLayer->resize(mouseEvent, m_offsetFromResizeCorner);
1617 else {
1618 if (FrameView* view = m_frame->view())
1619 scrollbar = view->scrollbarAtPoint(mouseEvent.pos());
1620
1621 if (!scrollbar)
1622 scrollbar = mev.scrollbar();
1623
1624 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1625 }
1626
1627 bool swallowEvent = false;
1628 RefPtr<Frame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1629
1630 // 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.
1631 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree()->isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1632 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1633
1634 if (newSubframe) {
1635 // Update over/out state before passing the event to the subframe.
1636 updateMouseEventTargetNode(targetNode(mev), mouseEvent, true);
1637
1638 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1639 // node to be detached from its FrameView, in which case the event should not be passed.
1640 if (newSubframe->view())
1641 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1642 } else {
1643 if (scrollbar && !m_mousePressed)
1644 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1645 if (Page* page = m_frame->page()) {
1646 if ((!m_resizeLayer || !m_resizeLayer->inResizeMode()) && !page->mainFrame()->eventHandler()->panScrollInProgress()) {
1647 // Plugins set cursor on their own. The only case WebKit intervenes is resetting cursor to arrow on mouse enter,
1648 // in case the particular plugin doesn't manipulate cursor at all. Thus, even a CSS cursor set on body has no
1649 // effect on plugins (which matches Firefox).
1650 bool overPluginElement = false;
1651 if (targetNode(mev) && targetNode(mev)->isHTMLElement()) {
1652 HTMLElement* el = toHTMLElement(targetNode(mev));
1653 overPluginElement = el->hasTagName(appletTag) || el->hasTagName(objectTag) || el->hasTagName(embedTag);
1654 }
1655 if (!overPluginElement) {
1656 if (FrameView* view = m_frame->view())
1657 view->setCursor(selectCursor(mev, scrollbar));
1658 }
1659 }
1660 }
1661 }
1662
1663 m_lastMouseMoveEventSubframe = newSubframe;
1664
1665 if (swallowEvent)
1666 return true;
1667
1668 swallowEvent = dispatchMouseEvent(eventNames().mousemoveEvent, targetNode(mev), false, 0, mouseEvent, true);
1669 #if ENABLE(DRAG_SUPPORT)
1670 if (!swallowEvent)
1671 swallowEvent = handleMouseDraggedEvent(mev);
1672 #endif // ENABLE(DRAG_SUPPORT)
1673
1674 return swallowEvent;
1675 }
1676
invalidateClick()1677 void EventHandler::invalidateClick()
1678 {
1679 m_clickCount = 0;
1680 m_clickNode = 0;
1681 }
1682
handleMouseReleaseEvent(const PlatformMouseEvent & mouseEvent)1683 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1684 {
1685 RefPtr<FrameView> protector(m_frame->view());
1686
1687 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1688
1689 #if ENABLE(PAN_SCROLLING)
1690 if (mouseEvent.button() == MiddleButton)
1691 m_panScrollButtonPressed = false;
1692 if (m_springLoadedPanScrollInProgress)
1693 stopAutoscrollTimer();
1694 #endif
1695
1696 m_mousePressed = false;
1697 m_currentMousePosition = mouseEvent.pos();
1698
1699 #if ENABLE(SVG)
1700 if (m_svgPan) {
1701 m_svgPan = false;
1702 static_cast<SVGDocument*>(m_frame->document())->updatePan(m_currentMousePosition);
1703 return true;
1704 }
1705 #endif
1706
1707 if (m_frameSetBeingResized)
1708 return dispatchMouseEvent(eventNames().mouseupEvent, m_frameSetBeingResized.get(), true, m_clickCount, mouseEvent, false);
1709
1710 if (m_lastScrollbarUnderMouse) {
1711 invalidateClick();
1712 return m_lastScrollbarUnderMouse->mouseUp();
1713 }
1714
1715 #if ENABLE(COMPOSITED_FIXED_ELEMENTS)
1716 // Add IgnoreClipping because fixed position elements are moved only on the
1717 // UI thread. Nodes in fixed position elements are clipped out by the view
1718 // without IgnoreClipping.
1719 HitTestRequest request(HitTestRequest::MouseUp | HitTestRequest::IgnoreClipping);
1720 #else
1721 HitTestRequest request(HitTestRequest::MouseUp);
1722 #endif
1723 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1724 Frame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1725 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1726 m_capturingMouseEventsNode = 0;
1727 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1728 return true;
1729
1730 bool swallowMouseUpEvent = dispatchMouseEvent(eventNames().mouseupEvent, targetNode(mev), true, m_clickCount, mouseEvent, false);
1731
1732 bool swallowClickEvent = m_clickCount > 0 && mouseEvent.button() != RightButton && targetNode(mev) == m_clickNode && dispatchMouseEvent(eventNames().clickEvent, targetNode(mev), true, m_clickCount, mouseEvent, true);
1733
1734 if (m_resizeLayer) {
1735 m_resizeLayer->setInResizeMode(false);
1736 m_resizeLayer = 0;
1737 }
1738
1739 bool swallowMouseReleaseEvent = false;
1740 if (!swallowMouseUpEvent)
1741 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1742
1743 invalidateClick();
1744
1745 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1746 }
1747
1748 #if ENABLE(DRAG_SUPPORT)
dispatchDragEvent(const AtomicString & eventType,Node * dragTarget,const PlatformMouseEvent & event,Clipboard * clipboard)1749 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1750 {
1751 FrameView* view = m_frame->view();
1752
1753 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1754 if (!view)
1755 return false;
1756
1757 view->resetDeferredRepaintDelay();
1758 RefPtr<MouseEvent> me = MouseEvent::create(eventType,
1759 true, true, m_frame->document()->defaultView(),
1760 0, event.globalX(), event.globalY(), event.x(), event.y(),
1761 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1762 0, 0, clipboard);
1763
1764 ExceptionCode ec;
1765 dragTarget->dispatchEvent(me.get(), ec);
1766 return me->defaultPrevented();
1767 }
1768
canHandleDragAndDropForTarget(DragAndDropHandleType type,Node * target,const PlatformMouseEvent & event,Clipboard * clipboard,bool * accepted)1769 bool EventHandler::canHandleDragAndDropForTarget(DragAndDropHandleType type, Node* target, const PlatformMouseEvent& event, Clipboard* clipboard, bool* accepted)
1770 {
1771 bool canHandle = false;
1772 bool wasAccepted = false;
1773
1774 if (target->hasTagName(frameTag) || target->hasTagName(iframeTag)) {
1775 Frame* frame = static_cast<HTMLFrameElementBase*>(target)->contentFrame();
1776 if (frame) {
1777 switch (type) {
1778 case UpdateDragAndDrop:
1779 wasAccepted = frame->eventHandler()->updateDragAndDrop(event, clipboard);
1780 break;
1781 case CancelDragAndDrop:
1782 frame->eventHandler()->cancelDragAndDrop(event, clipboard);
1783 break;
1784 case PerformDragAndDrop:
1785 wasAccepted = frame->eventHandler()->performDragAndDrop(event, clipboard);
1786 break;
1787 }
1788 }
1789 } else
1790 canHandle = true;
1791
1792 if (accepted)
1793 *accepted = wasAccepted;
1794
1795 return canHandle;
1796 }
1797
updateDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1798 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1799 {
1800 bool accept = false;
1801
1802 if (!m_frame->view())
1803 return false;
1804
1805 HitTestRequest request(HitTestRequest::ReadOnly);
1806 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1807
1808 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1809 Node* newTarget = targetNode(mev);
1810 if (newTarget && newTarget->isTextNode())
1811 newTarget = newTarget->parentNode();
1812 if (newTarget)
1813 newTarget = newTarget->shadowAncestorNode();
1814
1815 if (m_dragTarget != newTarget) {
1816 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1817 // it is sometimes incorrect when dragging within subframes, as seen with
1818 // LayoutTests/fast/events/drag-in-frames.html.
1819 //
1820 // Moreover, this ordering conforms to section 7.9.4 of the HTML 5 spec. <http://dev.w3.org/html5/spec/Overview.html#drag-and-drop-processing-model>.
1821 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
1822 // As per section 7.9.4 of the HTML 5 spec., we must always fire a drag event before firing a dragenter, dragleave, or dragover event.
1823 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
1824 // for now we don't care if event handler cancels default behavior, since there is none
1825 dispatchDragSrcEvent(eventNames().dragEvent, event);
1826 }
1827 accept = dispatchDragEvent(eventNames().dragenterEvent, newTarget, event, clipboard);
1828 }
1829
1830 if (m_dragTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
1831 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1832
1833 if (newTarget) {
1834 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1835 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1836 m_shouldOnlyFireDragOverEvent = true;
1837 }
1838 } else {
1839 if (newTarget && canHandleDragAndDropForTarget(UpdateDragAndDrop, newTarget, event, clipboard, &accept)) {
1840 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1841 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
1842 // for now we don't care if event handler cancels default behavior, since there is none
1843 dispatchDragSrcEvent(eventNames().dragEvent, event);
1844 }
1845 accept = dispatchDragEvent(eventNames().dragoverEvent, newTarget, event, clipboard);
1846 m_shouldOnlyFireDragOverEvent = false;
1847 }
1848 }
1849 m_dragTarget = newTarget;
1850
1851 return accept;
1852 }
1853
cancelDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1854 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1855 {
1856 if (m_dragTarget && canHandleDragAndDropForTarget(CancelDragAndDrop, m_dragTarget.get(), event, clipboard)) {
1857 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML)
1858 dispatchDragSrcEvent(eventNames().dragEvent, event);
1859 dispatchDragEvent(eventNames().dragleaveEvent, m_dragTarget.get(), event, clipboard);
1860 }
1861 clearDragState();
1862 }
1863
performDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1864 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1865 {
1866 bool accept = false;
1867 if (m_dragTarget && canHandleDragAndDropForTarget(PerformDragAndDrop, m_dragTarget.get(), event, clipboard, &accept))
1868 dispatchDragEvent(eventNames().dropEvent, m_dragTarget.get(), event, clipboard);
1869 clearDragState();
1870 return accept;
1871 }
1872
clearDragState()1873 void EventHandler::clearDragState()
1874 {
1875 m_dragTarget = 0;
1876 m_capturingMouseEventsNode = 0;
1877 m_shouldOnlyFireDragOverEvent = false;
1878 #if PLATFORM(MAC)
1879 m_sendingEventToSubview = false;
1880 #endif
1881 }
1882 #endif // ENABLE(DRAG_SUPPORT)
1883
1884 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
setCapturingTouchEventsNode(PassRefPtr<Node> n)1885 void EventHandler::setCapturingTouchEventsNode(PassRefPtr<Node> n)
1886 {
1887 m_capturingTouchEventsNode = n;
1888 }
1889 #endif
1890
setCapturingMouseEventsNode(PassRefPtr<Node> n)1891 void EventHandler::setCapturingMouseEventsNode(PassRefPtr<Node> n)
1892 {
1893 m_capturingMouseEventsNode = n;
1894 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1895 }
1896
prepareMouseEvent(const HitTestRequest & request,const PlatformMouseEvent & mev)1897 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1898 {
1899 ASSERT(m_frame);
1900 ASSERT(m_frame->document());
1901
1902 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.pos()), mev);
1903 }
1904
1905 #if ENABLE(SVG)
instanceAssociatedWithShadowTreeElement(Node * referenceNode)1906 static inline SVGElementInstance* instanceAssociatedWithShadowTreeElement(Node* referenceNode)
1907 {
1908 if (!referenceNode || !referenceNode->isSVGElement())
1909 return 0;
1910
1911 Node* shadowTreeElement = referenceNode->shadowTreeRootNode();
1912 if (!shadowTreeElement)
1913 return 0;
1914
1915 Element* shadowTreeParentElement = shadowTreeElement->shadowHost();
1916 if (!shadowTreeParentElement)
1917 return 0;
1918
1919 ASSERT(shadowTreeParentElement->hasTagName(useTag));
1920 return static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode);
1921 }
1922 #endif
1923
updateMouseEventTargetNode(Node * targetNode,const PlatformMouseEvent & mouseEvent,bool fireMouseOverOut)1924 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1925 {
1926 Node* result = targetNode;
1927
1928 // If we're capturing, we always go right to that node.
1929 if (m_capturingMouseEventsNode)
1930 result = m_capturingMouseEventsNode.get();
1931 else {
1932 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1933 if (result && result->isTextNode())
1934 result = result->parentNode();
1935 }
1936 m_nodeUnderMouse = result;
1937 #if ENABLE(SVG)
1938 m_instanceUnderMouse = instanceAssociatedWithShadowTreeElement(result);
1939
1940 // <use> shadow tree elements may have been recloned, update node under mouse in any case
1941 if (m_lastInstanceUnderMouse) {
1942 SVGElement* lastCorrespondingElement = m_lastInstanceUnderMouse->correspondingElement();
1943 SVGElement* lastCorrespondingUseElement = m_lastInstanceUnderMouse->correspondingUseElement();
1944
1945 if (lastCorrespondingElement && lastCorrespondingUseElement) {
1946 HashSet<SVGElementInstance*> instances = lastCorrespondingElement->instancesForElement();
1947
1948 // Locate the recloned shadow tree element for our corresponding instance
1949 HashSet<SVGElementInstance*>::iterator end = instances.end();
1950 for (HashSet<SVGElementInstance*>::iterator it = instances.begin(); it != end; ++it) {
1951 SVGElementInstance* instance = (*it);
1952 ASSERT(instance->correspondingElement() == lastCorrespondingElement);
1953
1954 if (instance == m_lastInstanceUnderMouse)
1955 continue;
1956
1957 if (instance->correspondingUseElement() != lastCorrespondingUseElement)
1958 continue;
1959
1960 SVGElement* shadowTreeElement = instance->shadowTreeElement();
1961 if (!shadowTreeElement->inDocument() || m_lastNodeUnderMouse == shadowTreeElement)
1962 continue;
1963
1964 m_lastNodeUnderMouse = shadowTreeElement;
1965 m_lastInstanceUnderMouse = instance;
1966 break;
1967 }
1968 }
1969 }
1970 #endif
1971
1972 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1973 if (fireMouseOverOut) {
1974 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1975 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1976 Page* page = m_frame->page();
1977
1978 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1979 // The mouse has moved between frames.
1980 if (Frame* frame = m_lastNodeUnderMouse->document()->frame()) {
1981 if (FrameView* frameView = frame->view())
1982 frameView->scrollAnimator()->mouseExitedContentArea();
1983 }
1984 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1985 // The mouse has moved between layers.
1986 if (page->containsScrollableArea(layerForLastNode))
1987 layerForLastNode->scrollAnimator()->mouseExitedContentArea();
1988 }
1989
1990 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1991 // The mouse has moved between frames.
1992 if (Frame* frame = m_nodeUnderMouse->document()->frame()) {
1993 if (FrameView* frameView = frame->view())
1994 frameView->scrollAnimator()->mouseEnteredContentArea();
1995 }
1996 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1997 // The mouse has moved between layers.
1998 if (page->containsScrollableArea(layerForNodeUnderMouse))
1999 layerForNodeUnderMouse->scrollAnimator()->mouseEnteredContentArea();
2000 }
2001
2002 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
2003 m_lastNodeUnderMouse = 0;
2004 m_lastScrollbarUnderMouse = 0;
2005 #if ENABLE(SVG)
2006 m_lastInstanceUnderMouse = 0;
2007 #endif
2008 }
2009
2010 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
2011 // send mouseout event to the old node
2012 if (m_lastNodeUnderMouse)
2013 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoutEvent, 0, m_nodeUnderMouse.get());
2014 // send mouseover event to the new node
2015 if (m_nodeUnderMouse)
2016 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventNames().mouseoverEvent, 0, m_lastNodeUnderMouse.get());
2017 }
2018 m_lastNodeUnderMouse = m_nodeUnderMouse;
2019 #if ENABLE(SVG)
2020 m_lastInstanceUnderMouse = instanceAssociatedWithShadowTreeElement(m_nodeUnderMouse.get());
2021 #endif
2022 }
2023 }
2024
dispatchMouseEvent(const AtomicString & eventType,Node * targetNode,bool,int clickCount,const PlatformMouseEvent & mouseEvent,bool setUnder)2025 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, bool /*cancelable*/, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
2026 {
2027 if (FrameView* view = m_frame->view())
2028 view->resetDeferredRepaintDelay();
2029
2030 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
2031
2032 bool swallowEvent = false;
2033
2034 if (m_nodeUnderMouse)
2035 swallowEvent = m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
2036
2037 if (!swallowEvent && eventType == eventNames().mousedownEvent) {
2038
2039 // If clicking on a frame scrollbar, do not mess up with content focus.
2040 if (FrameView* view = m_frame->view()) {
2041 if (view->scrollbarAtPoint(mouseEvent.pos()))
2042 return false;
2043 }
2044
2045 // The layout needs to be up to date to determine if an element is focusable.
2046 m_frame->document()->updateLayoutIgnorePendingStylesheets();
2047
2048 // Blur current focus node when a link/button is clicked; this
2049 // is expected by some sites that rely on onChange handlers running
2050 // from form fields before the button click is processed.
2051 Node* node = m_nodeUnderMouse.get();
2052
2053 // Walk up the DOM tree to search for a node to focus.
2054 while (node) {
2055 if (node->isMouseFocusable()) {
2056 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus a
2057 // node on mouse down if it's selected and inside a focused node. It will be
2058 // focused if the user does a mouseup over it, however, because the mouseup
2059 // will set a selection inside it, which will call setFocuseNodeIfNeeded.
2060 ExceptionCode ec = 0;
2061 Node* n = node->isShadowRoot() ? node->shadowHost() : node;
2062 if (m_frame->selection()->isRange()
2063 && m_frame->selection()->toNormalizedRange()->compareNode(n, ec) == Range::NODE_INSIDE
2064 && n->isDescendantOf(m_frame->document()->focusedNode()))
2065 return false;
2066
2067 break;
2068 }
2069 node = node->parentOrHostNode();
2070 }
2071
2072 // If focus shift is blocked, we eat the event. Note we should never clear swallowEvent
2073 // if the page already set it (e.g., by canceling default behavior).
2074 if (Page* page = m_frame->page()) {
2075 if (node && node->isMouseFocusable()) {
2076 if (!page->focusController()->setFocusedNode(node, m_frame))
2077 swallowEvent = true;
2078 } else if (!node || !node->focused()) {
2079 if (!page->focusController()->setFocusedNode(0, m_frame))
2080 swallowEvent = true;
2081 }
2082 }
2083 }
2084
2085 return swallowEvent;
2086 }
2087
2088 #if !PLATFORM(GTK) && !(PLATFORM(CHROMIUM) && (OS(LINUX) || OS(FREEBSD)))
shouldTurnVerticalTicksIntoHorizontal(const HitTestResult &) const2089 bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const
2090 {
2091 return false;
2092 }
2093 #endif
2094
handleWheelEvent(PlatformWheelEvent & e)2095 bool EventHandler::handleWheelEvent(PlatformWheelEvent& e)
2096 {
2097 Document* doc = m_frame->document();
2098
2099 RenderObject* docRenderer = doc->renderer();
2100 if (!docRenderer)
2101 return false;
2102
2103 RefPtr<FrameView> protector(m_frame->view());
2104
2105 FrameView* view = m_frame->view();
2106 if (!view)
2107 return false;
2108 setFrameWasScrolledByUser();
2109 IntPoint vPoint = view->windowToContents(e.pos());
2110
2111 Node* node;
2112 bool isOverWidget;
2113
2114 HitTestRequest request(HitTestRequest::ReadOnly);
2115 HitTestResult result(vPoint);
2116 doc->renderView()->layer()->hitTest(request, result);
2117
2118 #if PLATFORM(MAC)
2119 m_useLatchedWheelEventNode = e.momentumPhase() == PlatformWheelEventPhaseBegan || e.momentumPhase() == PlatformWheelEventPhaseChanged;
2120 #endif
2121
2122 if (m_useLatchedWheelEventNode) {
2123 if (!m_latchedWheelEventNode) {
2124 m_latchedWheelEventNode = result.innerNode();
2125 m_widgetIsLatched = result.isOverWidget();
2126 }
2127
2128 node = m_latchedWheelEventNode.get();
2129 isOverWidget = m_widgetIsLatched;
2130 } else {
2131 if (m_latchedWheelEventNode)
2132 m_latchedWheelEventNode = 0;
2133 if (m_previousWheelScrolledNode)
2134 m_previousWheelScrolledNode = 0;
2135
2136 node = result.innerNode();
2137 isOverWidget = result.isOverWidget();
2138 }
2139
2140 if (shouldTurnVerticalTicksIntoHorizontal(result))
2141 e.turnVerticalTicksIntoHorizontal();
2142
2143 if (node) {
2144 // Figure out which view to send the event to.
2145 RenderObject* target = node->renderer();
2146
2147 if (isOverWidget && target && target->isWidget()) {
2148 Widget* widget = toRenderWidget(target)->widget();
2149 if (widget && passWheelEventToWidget(e, widget)) {
2150 e.accept();
2151 return true;
2152 }
2153 }
2154
2155 node = node->shadowAncestorNode();
2156 if (!node->dispatchWheelEvent(e)) {
2157 e.accept();
2158 return true;
2159 }
2160 }
2161
2162 if (e.isAccepted())
2163 return true;
2164
2165 view = m_frame->view();
2166 if (!view)
2167 return false;
2168
2169 view->wheelEvent(e);
2170 return e.isAccepted();
2171 }
2172
defaultWheelEventHandler(Node * startNode,WheelEvent * wheelEvent)2173 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2174 {
2175 if (!startNode || !wheelEvent)
2176 return;
2177
2178 Node* stopNode = m_previousWheelScrolledNode.get();
2179
2180 // Break up into two scrolls if we need to. Diagonal movement on
2181 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2182 if (scrollNode(wheelEvent->rawDeltaX(), wheelEvent->granularity(), ScrollLeft, ScrollRight, startNode, &stopNode))
2183 wheelEvent->setDefaultHandled();
2184
2185 if (scrollNode(wheelEvent->rawDeltaY(), wheelEvent->granularity(), ScrollUp, ScrollDown, startNode, &stopNode))
2186 wheelEvent->setDefaultHandled();
2187
2188 if (!m_useLatchedWheelEventNode)
2189 m_previousWheelScrolledNode = stopNode;
2190 }
2191
2192 #if ENABLE(GESTURE_EVENTS)
handleGestureEvent(const PlatformGestureEvent & gestureEvent)2193 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2194 {
2195 // FIXME: This should hit test and go to the correct subframe rather than
2196 // always sending gestures to the main frame only. We should also ensure
2197 // that if a frame gets a gesture begin gesture, it gets the corresponding
2198 // end gesture as well.
2199
2200 FrameView* view = m_frame->view();
2201 if (!view)
2202 return false;
2203
2204 view->handleGestureEvent(gestureEvent);
2205 return true;
2206 }
2207 #endif
2208
2209 #if ENABLE(CONTEXT_MENUS)
sendContextMenuEvent(const PlatformMouseEvent & event)2210 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2211 {
2212 Document* doc = m_frame->document();
2213 FrameView* v = m_frame->view();
2214 if (!v)
2215 return false;
2216
2217 bool swallowEvent;
2218 IntPoint viewportPos = v->windowToContents(event.pos());
2219 HitTestRequest request(HitTestRequest::Active);
2220 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2221
2222 if (m_frame->editor()->behavior().shouldSelectOnContextualMenuClick()
2223 && !m_frame->selection()->contains(viewportPos)
2224 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2225 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2226 // available for text selections. But only if we're above text.
2227 && (m_frame->selection()->isContentEditable() || (targetNode(mev) && targetNode(mev)->isTextNode()))) {
2228 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2229 selectClosestWordOrLinkFromMouseEvent(mev);
2230 }
2231
2232 swallowEvent = dispatchMouseEvent(eventNames().contextmenuEvent, targetNode(mev), true, 0, event, false);
2233
2234 return swallowEvent;
2235 }
2236
sendContextMenuEventForKey()2237 bool EventHandler::sendContextMenuEventForKey()
2238 {
2239 FrameView* view = m_frame->view();
2240 if (!view)
2241 return false;
2242
2243 Document* doc = m_frame->document();
2244 if (!doc)
2245 return false;
2246
2247 static const int kContextMenuMargin = 1;
2248
2249 #if OS(WINDOWS) && !OS(WINCE)
2250 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2251 #else
2252 int rightAligned = 0;
2253 #endif
2254 IntPoint location;
2255
2256 Node* focusedNode = doc->focusedNode();
2257 SelectionController* selectionController = m_frame->selection();
2258 Position start = selectionController->selection().start();
2259
2260 if (start.deprecatedNode() && (selectionController->rootEditableElement() || selectionController->isRange())) {
2261 RefPtr<Range> selection = selectionController->toNormalizedRange();
2262 IntRect firstRect = m_frame->editor()->firstRectForRange(selection.get());
2263
2264 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2265 location = IntPoint(x, firstRect.maxY());
2266 } else if (focusedNode) {
2267 RenderBoxModelObject* box = focusedNode->renderBoxModelObject();
2268 if (!box)
2269 return false;
2270 IntRect clippedRect = box->absoluteClippedOverflowRect();
2271 location = IntPoint(clippedRect.x(), clippedRect.maxY() - 1);
2272 } else {
2273 location = IntPoint(
2274 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2275 kContextMenuMargin);
2276 }
2277
2278 m_frame->view()->setCursor(pointerCursor());
2279
2280 IntPoint position = view->contentsToWindow(location);
2281 IntPoint globalPosition = view->contentsToScreen(IntRect(location, IntSize())).location();
2282
2283 Node* targetNode = doc->focusedNode();
2284 if (!targetNode)
2285 targetNode = doc;
2286
2287 // Use the focused node as the target for hover and active.
2288 HitTestResult result(position);
2289 result.setInnerNode(targetNode);
2290 HitTestRequest request(HitTestRequest::Active);
2291 doc->renderView()->layer()->updateHoverActiveState(request, result);
2292 doc->updateStyleIfNeeded();
2293
2294 // The contextmenu event is a mouse event even when invoked using the keyboard.
2295 // This is required for web compatibility.
2296
2297 #if OS(WINDOWS)
2298 MouseEventType eventType = MouseEventReleased;
2299 #else
2300 MouseEventType eventType = MouseEventPressed;
2301 #endif
2302
2303 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2304
2305 return dispatchMouseEvent(eventNames().contextmenuEvent, targetNode, true, 0, mouseEvent, false);
2306 }
2307
2308 #endif // ENABLE(CONTEXT_MENUS)
2309
scheduleHoverStateUpdate()2310 void EventHandler::scheduleHoverStateUpdate()
2311 {
2312 if (!m_hoverTimer.isActive())
2313 m_hoverTimer.startOneShot(0);
2314 }
2315
dispatchFakeMouseMoveEventSoon()2316 void EventHandler::dispatchFakeMouseMoveEventSoon()
2317 {
2318 if (m_mousePressed)
2319 return;
2320
2321 if (!m_fakeMouseMoveEventTimer.isActive())
2322 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2323 }
2324
dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad & quad)2325 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2326 {
2327 FrameView* view = m_frame->view();
2328 if (!view)
2329 return;
2330
2331 if (m_mousePressed || !quad.containsPoint(view->windowToContents(m_currentMousePosition)))
2332 return;
2333
2334 if (!m_fakeMouseMoveEventTimer.isActive())
2335 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveInterval);
2336 }
2337
cancelFakeMouseMoveEvent()2338 void EventHandler::cancelFakeMouseMoveEvent()
2339 {
2340 m_fakeMouseMoveEventTimer.stop();
2341 }
2342
fakeMouseMoveEventTimerFired(Timer<EventHandler> * timer)2343 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2344 {
2345 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2346 ASSERT(!m_mousePressed);
2347
2348 FrameView* view = m_frame->view();
2349 if (!view)
2350 return;
2351
2352 bool shiftKey;
2353 bool ctrlKey;
2354 bool altKey;
2355 bool metaKey;
2356 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2357 IntPoint globalPoint = view->contentsToScreen(IntRect(view->windowToContents(m_currentMousePosition), IntSize())).location();
2358 PlatformMouseEvent fakeMouseMoveEvent(m_currentMousePosition, globalPoint, NoButton, MouseEventMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2359 mouseMoved(fakeMouseMoveEvent);
2360 }
2361
2362 // Whether or not a mouse down can begin the creation of a selection. Fires the selectStart event.
canMouseDownStartSelect(Node * node)2363 bool EventHandler::canMouseDownStartSelect(Node* node)
2364 {
2365 if (!node || !node->renderer())
2366 return true;
2367
2368 // Some controls and images can't start a select on a mouse down.
2369 if (!node->canStartSelection())
2370 return false;
2371
2372 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
2373 }
2374
2375 #if ENABLE(DRAG_SUPPORT)
canMouseDragExtendSelect(Node * node)2376 bool EventHandler::canMouseDragExtendSelect(Node* node)
2377 {
2378 if (!node || !node->renderer())
2379 return true;
2380
2381 return node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true));
2382 }
2383 #endif // ENABLE(DRAG_SUPPORT)
2384
setResizingFrameSet(HTMLFrameSetElement * frameSet)2385 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2386 {
2387 m_frameSetBeingResized = frameSet;
2388 }
2389
resizeLayerDestroyed()2390 void EventHandler::resizeLayerDestroyed()
2391 {
2392 ASSERT(m_resizeLayer);
2393 m_resizeLayer = 0;
2394 }
2395
hoverTimerFired(Timer<EventHandler> *)2396 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2397 {
2398 m_hoverTimer.stop();
2399
2400 ASSERT(m_frame);
2401 ASSERT(m_frame->document());
2402
2403 if (RenderView* renderer = m_frame->contentRenderer()) {
2404 if (FrameView* view = m_frame->view()) {
2405 HitTestRequest request(HitTestRequest::MouseMove);
2406 HitTestResult result(view->windowToContents(m_currentMousePosition));
2407 renderer->layer()->hitTest(request, result);
2408 m_frame->document()->updateStyleIfNeeded();
2409 }
2410 }
2411 }
2412
eventTargetNodeForDocument(Document * doc)2413 static Node* eventTargetNodeForDocument(Document* doc)
2414 {
2415 if (!doc)
2416 return 0;
2417 Node* node = doc->focusedNode();
2418 #if defined(ANDROID_PLUGINS)
2419 if (!node && doc->frame() && doc->frame()->view())
2420 node = android::WebViewCore::getWebViewCore(doc->frame()->view())
2421 ->cursorNodeIsPlugin();
2422 #else
2423 if (!node && doc->isPluginDocument()) {
2424 PluginDocument* pluginDocument = static_cast<PluginDocument*>(doc);
2425 node = pluginDocument->pluginNode();
2426 }
2427 #endif
2428 if (!node && doc->isHTMLDocument())
2429 node = doc->body();
2430 if (!node)
2431 node = doc->documentElement();
2432 return node;
2433 }
2434
handleAccessKey(const PlatformKeyboardEvent & evt)2435 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2436 {
2437 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2438 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2439 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2440 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2441 ASSERT(!(accessKeyModifiers() & PlatformKeyboardEvent::ShiftKey));
2442 if ((evt.modifiers() & ~PlatformKeyboardEvent::ShiftKey) != accessKeyModifiers())
2443 return false;
2444 String key = evt.unmodifiedText();
2445 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2446 if (!elem)
2447 return false;
2448 elem->accessKeyAction(false);
2449 return true;
2450 }
2451
2452 #if !PLATFORM(MAC)
needsKeyboardEventDisambiguationQuirks() const2453 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
2454 {
2455 return false;
2456 }
2457 #endif
2458
keyEvent(const PlatformKeyboardEvent & initialKeyEvent)2459 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2460 {
2461 RefPtr<FrameView> protector(m_frame->view());
2462
2463 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2464 capsLockStateMayHaveChanged();
2465
2466 #if ENABLE(PAN_SCROLLING)
2467 if (Page* page = m_frame->page()) {
2468 if (page->mainFrame()->eventHandler()->panScrollInProgress() || m_autoscrollInProgress) {
2469 // If a key is pressed while the autoscroll/panScroll is in progress then we want to stop
2470 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown || initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown)
2471 stopAutoscrollTimer();
2472
2473 // If we were in autoscroll/panscroll mode, we swallow the key event
2474 return true;
2475 }
2476 }
2477 #endif
2478
2479 // Check for cases where we are too early for events -- possible unmatched key up
2480 // from pressing return in the location bar.
2481 RefPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2482 if (!node)
2483 return false;
2484
2485 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2486 UserTypingGestureIndicator typingGestureIndicator(m_frame);
2487
2488 if (FrameView* view = m_frame->view())
2489 view->resetDeferredRepaintDelay();
2490
2491 // FIXME: what is this doing here, in keyboard event handler?
2492 m_frame->loader()->resetMultipleFormSubmissionProtection();
2493
2494 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2495 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2496 // with access keys. Then we dispatch keydown, but suppress its default handling.
2497 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2498 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2499 bool matchedAnAccessKey = false;
2500 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyDown)
2501 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2502
2503 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2504 if (initialKeyEvent.type() == PlatformKeyboardEvent::KeyUp || initialKeyEvent.type() == PlatformKeyboardEvent::Char)
2505 return !node->dispatchKeyEvent(initialKeyEvent);
2506
2507 bool backwardCompatibilityMode = needsKeyboardEventDisambiguationQuirks();
2508
2509 ExceptionCode ec;
2510 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2511 if (keyDownEvent.type() != PlatformKeyboardEvent::RawKeyDown)
2512 keyDownEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown, backwardCompatibilityMode);
2513 RefPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2514 if (matchedAnAccessKey)
2515 keydown->setDefaultPrevented(true);
2516 keydown->setTarget(node);
2517
2518 if (initialKeyEvent.type() == PlatformKeyboardEvent::RawKeyDown) {
2519 node->dispatchEvent(keydown, ec);
2520 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2521 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2522 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2523 }
2524
2525 // Run input method in advance of DOM event handling. This may result in the IM
2526 // modifying the page prior the keydown event, but this behaviour is necessary
2527 // in order to match IE:
2528 // 1. preventing default handling of keydown and keypress events has no effect on IM input;
2529 // 2. if an input method handles the event, its keyCode is set to 229 in keydown event.
2530 m_frame->editor()->handleInputMethodKeydown(keydown.get());
2531
2532 bool handledByInputMethod = keydown->defaultHandled();
2533
2534 if (handledByInputMethod) {
2535 keyDownEvent.setWindowsVirtualKeyCode(CompositionEventKeyCode);
2536 keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->defaultView());
2537 keydown->setTarget(node);
2538 keydown->setDefaultHandled();
2539 }
2540
2541 node->dispatchEvent(keydown, ec);
2542 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2543 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController()->focusedOrMainFrame();
2544 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2545 if (handledByInputMethod || (keydownResult && !backwardCompatibilityMode))
2546 return keydownResult;
2547
2548 // Focus may have changed during keydown handling, so refetch node.
2549 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2550 if (!keydownResult) {
2551 node = eventTargetNodeForDocument(m_frame->document());
2552 if (!node)
2553 return false;
2554 }
2555
2556 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2557 keyPressEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::Char, backwardCompatibilityMode);
2558 if (keyPressEvent.text().isEmpty())
2559 return keydownResult;
2560 RefPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->defaultView());
2561 keypress->setTarget(node);
2562 if (keydownResult)
2563 keypress->setDefaultPrevented(true);
2564 #if PLATFORM(MAC)
2565 keypress->keypressCommands() = keydown->keypressCommands();
2566 #endif
2567 node->dispatchEvent(keypress, ec);
2568
2569 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2570 }
2571
handleKeyboardSelectionMovement(KeyboardEvent * event)2572 void EventHandler::handleKeyboardSelectionMovement(KeyboardEvent* event)
2573 {
2574 if (!event)
2575 return;
2576
2577 const String& key = event->keyIdentifier();
2578 bool isShifted = event->getModifierState("Shift");
2579 bool isOptioned = event->getModifierState("Alt");
2580 bool isCommanded = event->getModifierState("Meta");
2581
2582 if (key == "Up") {
2583 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionBackward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2584 event->setDefaultHandled();
2585 } else if (key == "Down") {
2586 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionForward, (isCommanded) ? DocumentBoundary : LineGranularity, true);
2587 event->setDefaultHandled();
2588 } else if (key == "Left") {
2589 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionLeft, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2590 event->setDefaultHandled();
2591 } else if (key == "Right") {
2592 m_frame->selection()->modify((isShifted) ? SelectionController::AlterationExtend : SelectionController::AlterationMove, DirectionRight, (isCommanded) ? LineBoundary : (isOptioned) ? WordGranularity : CharacterGranularity, true);
2593 event->setDefaultHandled();
2594 }
2595 }
2596
defaultKeyboardEventHandler(KeyboardEvent * event)2597 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2598 {
2599 if (event->type() == eventNames().keydownEvent) {
2600 m_frame->editor()->handleKeyboardEvent(event);
2601 if (event->defaultHandled())
2602 return;
2603 if (event->keyIdentifier() == "U+0009")
2604 defaultTabEventHandler(event);
2605 else if (event->keyIdentifier() == "U+0008")
2606 defaultBackspaceEventHandler(event);
2607 else {
2608 FocusDirection direction = focusDirectionForKey(event->keyIdentifier());
2609 if (direction != FocusDirectionNone)
2610 defaultArrowEventHandler(direction, event);
2611 }
2612
2613 // provides KB navigation and selection for enhanced accessibility users
2614 if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
2615 handleKeyboardSelectionMovement(event);
2616 }
2617 if (event->type() == eventNames().keypressEvent) {
2618 m_frame->editor()->handleKeyboardEvent(event);
2619 if (event->defaultHandled())
2620 return;
2621 if (event->charCode() == ' ')
2622 defaultSpaceEventHandler(event);
2623 }
2624 }
2625
focusDirectionForKey(const AtomicString & keyIdentifier) const2626 FocusDirection EventHandler::focusDirectionForKey(const AtomicString& keyIdentifier) const
2627 {
2628 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
2629 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
2630 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
2631 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
2632
2633 FocusDirection retVal = FocusDirectionNone;
2634
2635 if (keyIdentifier == Down)
2636 retVal = FocusDirectionDown;
2637 else if (keyIdentifier == Up)
2638 retVal = FocusDirectionUp;
2639 else if (keyIdentifier == Left)
2640 retVal = FocusDirectionLeft;
2641 else if (keyIdentifier == Right)
2642 retVal = FocusDirectionRight;
2643
2644 return retVal;
2645 }
2646
2647 #if ENABLE(DRAG_SUPPORT)
dragHysteresisExceeded(const FloatPoint & floatDragViewportLocation) const2648 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
2649 {
2650 IntPoint dragViewportLocation((int)floatDragViewportLocation.x(), (int)floatDragViewportLocation.y());
2651 return dragHysteresisExceeded(dragViewportLocation);
2652 }
2653
dragHysteresisExceeded(const IntPoint & dragViewportLocation) const2654 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
2655 {
2656 FrameView* view = m_frame->view();
2657 if (!view)
2658 return false;
2659 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
2660 IntSize delta = dragLocation - m_mouseDownPos;
2661
2662 int threshold = GeneralDragHysteresis;
2663 if (dragState().m_dragSrcIsImage)
2664 threshold = ImageDragHysteresis;
2665 else if (dragState().m_dragSrcIsLink)
2666 threshold = LinkDragHysteresis;
2667 else if (dragState().m_dragSrcInSelection)
2668 threshold = TextDragHysteresis;
2669
2670 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
2671 }
2672
freeClipboard()2673 void EventHandler::freeClipboard()
2674 {
2675 if (dragState().m_dragClipboard)
2676 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
2677 }
2678
shouldDragAutoNode(Node * node,const IntPoint & point) const2679 bool EventHandler::shouldDragAutoNode(Node* node, const IntPoint& point) const
2680 {
2681 if (!node || !m_frame->view())
2682 return false;
2683 Page* page = m_frame->page();
2684 return page && page->dragController()->mayStartDragAtEventLocation(m_frame, point, node);
2685 }
2686
dragSourceEndedAt(const PlatformMouseEvent & event,DragOperation operation)2687 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
2688 {
2689 if (dragState().m_dragSrc && dragState().m_dragSrcMayBeDHTML) {
2690 dragState().m_dragClipboard->setDestinationOperation(operation);
2691 // for now we don't care if event handler cancels default behavior, since there is none
2692 dispatchDragSrcEvent(eventNames().dragendEvent, event);
2693 }
2694 freeClipboard();
2695 dragState().m_dragSrc = 0;
2696 // In case the drag was ended due to an escape key press we need to ensure
2697 // that consecutive mousemove events don't reinitiate the drag and drop.
2698 m_mouseDownMayStartDrag = false;
2699 }
2700
2701 // returns if we should continue "default processing", i.e., whether eventhandler canceled
dispatchDragSrcEvent(const AtomicString & eventType,const PlatformMouseEvent & event)2702 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
2703 {
2704 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
2705 }
2706
handleDrag(const MouseEventWithHitTestResults & event)2707 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event)
2708 {
2709 if (event.event().button() != LeftButton || event.event().eventType() != MouseEventMoved) {
2710 // If we allowed the other side of the bridge to handle a drag
2711 // last time, then m_mousePressed might still be set. So we
2712 // clear it now to make sure the next move after a drag
2713 // doesn't look like a drag.
2714 m_mousePressed = false;
2715 return false;
2716 }
2717
2718 if (eventLoopHandleMouseDragged(event))
2719 return true;
2720
2721 // Careful that the drag starting logic stays in sync with eventMayStartDrag()
2722
2723 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2724 allowDHTMLDrag(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA);
2725 if (!dragState().m_dragSrcMayBeDHTML && !dragState().m_dragSrcMayBeUA)
2726 m_mouseDownMayStartDrag = false; // no element is draggable
2727 }
2728
2729 if (m_mouseDownMayStartDrag && !dragState().m_dragSrc) {
2730 // try to find an element that wants to be dragged
2731 HitTestRequest request(HitTestRequest::ReadOnly);
2732 HitTestResult result(m_mouseDownPos);
2733 m_frame->contentRenderer()->layer()->hitTest(request, result);
2734 Node* node = result.innerNode();
2735 if (node && node->renderer())
2736 dragState().m_dragSrc = node->renderer()->draggableNode(dragState().m_dragSrcMayBeDHTML, dragState().m_dragSrcMayBeUA,
2737 m_mouseDownPos.x(), m_mouseDownPos.y(), dragState().m_dragSrcIsDHTML);
2738 else
2739 dragState().m_dragSrc = 0;
2740
2741 if (!dragState().m_dragSrc)
2742 m_mouseDownMayStartDrag = false; // no element is draggable
2743 else {
2744 // remember some facts about this source, while we have a HitTestResult handy
2745 node = result.URLElement();
2746 dragState().m_dragSrcIsLink = node && node->isLink();
2747
2748 node = result.innerNonSharedNode();
2749 dragState().m_dragSrcIsImage = node && node->renderer() && node->renderer()->isImage();
2750
2751 dragState().m_dragSrcInSelection = m_frame->selection()->contains(m_mouseDownPos);
2752 }
2753 }
2754
2755 // For drags starting in the selection, the user must wait between the mousedown and mousedrag,
2756 // or else we bail on the dragging stuff and allow selection to occur
2757 if (m_mouseDownMayStartDrag && !dragState().m_dragSrcIsImage && dragState().m_dragSrcInSelection && event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay) {
2758 m_mouseDownMayStartDrag = false;
2759 dragState().m_dragSrc = 0;
2760 // ...but if this was the first click in the window, we don't even want to start selection
2761 if (eventActivatedView(event.event()))
2762 m_mouseDownMayStartSelect = false;
2763 }
2764
2765 if (!m_mouseDownMayStartDrag)
2766 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
2767
2768 // We are starting a text/image/url drag, so the cursor should be an arrow
2769 if (FrameView* view = m_frame->view()) {
2770 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
2771 view->setCursor(pointerCursor());
2772 }
2773
2774 if (!dragHysteresisExceeded(event.event().pos()))
2775 return true;
2776
2777 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
2778 invalidateClick();
2779
2780 DragOperation srcOp = DragOperationNone;
2781
2782 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
2783 // to make sure it gets numbified
2784 dragState().m_dragClipboard = createDraggingClipboard();
2785
2786 if (dragState().m_dragSrcMayBeDHTML) {
2787 // Check to see if the is a DOM based drag, if it is get the DOM specified drag
2788 // image and offset
2789 if (dragState().m_dragSrcIsDHTML) {
2790 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
2791 // FIXME: This doesn't work correctly with transforms.
2792 FloatPoint absPos = renderer->localToAbsolute();
2793 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
2794 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), toPoint(delta));
2795 } else {
2796 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
2797 // the element in some way. In this case we just kill the drag.
2798 m_mouseDownMayStartDrag = false;
2799 goto cleanupDrag;
2800 }
2801 }
2802
2803 m_mouseDownMayStartDrag = dispatchDragSrcEvent(eventNames().dragstartEvent, m_mouseDown)
2804 && !m_frame->selection()->isInPasswordField();
2805
2806 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
2807 // image can still be changed as we drag, but not the pasteboard data.
2808 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
2809
2810 if (m_mouseDownMayStartDrag) {
2811 // gather values from DHTML element, if it set any
2812 srcOp = dragState().m_dragClipboard->sourceOperation();
2813
2814 // Yuck, a draggedImage:moveTo: message can be fired as a result of kicking off the
2815 // drag with dragImage! Because of that dumb reentrancy, we may think we've not
2816 // started the drag when that happens. So we have to assume it's started before we
2817 // kick it off.
2818 dragState().m_dragClipboard->setDragHasStarted();
2819 }
2820 }
2821
2822 if (m_mouseDownMayStartDrag) {
2823 Page* page = m_frame->page();
2824 DragController* dragController = page ? page->dragController() : 0;
2825 bool startedDrag = dragController && dragController->startDrag(m_frame, dragState().m_dragClipboard.get(), srcOp, event.event(), m_mouseDownPos, dragState().m_dragSrcIsDHTML);
2826 if (!startedDrag && dragState().m_dragSrcMayBeDHTML) {
2827 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
2828 dispatchDragSrcEvent(eventNames().dragendEvent, event.event());
2829 m_mouseDownMayStartDrag = false;
2830 }
2831 }
2832
2833 cleanupDrag:
2834 if (!m_mouseDownMayStartDrag) {
2835 // something failed to start the drag, cleanup
2836 freeClipboard();
2837 dragState().m_dragSrc = 0;
2838 }
2839
2840 // No more default handling (like selection), whether we're past the hysteresis bounds or not
2841 return true;
2842 }
2843 #endif // ENABLE(DRAG_SUPPORT)
2844
handleTextInputEvent(const String & text,Event * underlyingEvent,TextEventInputType inputType)2845 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
2846 {
2847 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
2848 // and avoid dispatching text input events from keydown default handlers.
2849 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || static_cast<KeyboardEvent*>(underlyingEvent)->type() == eventNames().keypressEvent);
2850
2851 if (!m_frame)
2852 return false;
2853
2854 EventTarget* target;
2855 if (underlyingEvent)
2856 target = underlyingEvent->target();
2857 else
2858 target = eventTargetNodeForDocument(m_frame->document());
2859 if (!target)
2860 return false;
2861
2862 if (FrameView* view = m_frame->view())
2863 view->resetDeferredRepaintDelay();
2864
2865 RefPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
2866 event->setUnderlyingEvent(underlyingEvent);
2867
2868 ExceptionCode ec;
2869 target->dispatchEvent(event, ec);
2870 return event->defaultHandled();
2871 }
2872
isKeyboardOptionTab(KeyboardEvent * event)2873 bool EventHandler::isKeyboardOptionTab(KeyboardEvent* event)
2874 {
2875 return event
2876 && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
2877 && event->altKey()
2878 && event->keyIdentifier() == "U+0009";
2879 }
2880
eventInvertsTabsToLinksClientCallResult(KeyboardEvent * event)2881 static bool eventInvertsTabsToLinksClientCallResult(KeyboardEvent* event)
2882 {
2883 #if PLATFORM(MAC) || PLATFORM(QT) || PLATFORM(HAIKU) || PLATFORM(EFL)
2884 return EventHandler::isKeyboardOptionTab(event);
2885 #else
2886 return false;
2887 #endif
2888 }
2889
tabsToLinks(KeyboardEvent * event) const2890 bool EventHandler::tabsToLinks(KeyboardEvent* event) const
2891 {
2892 // FIXME: This function needs a better name. It can be called for keypresses other than Tab when spatial navigation is enabled.
2893
2894 Page* page = m_frame->page();
2895 if (!page)
2896 return false;
2897
2898 bool tabsToLinksClientCallResult = page->chrome()->client()->keyboardUIMode() & KeyboardAccessTabsToLinks;
2899 return eventInvertsTabsToLinksClientCallResult(event) ? !tabsToLinksClientCallResult : tabsToLinksClientCallResult;
2900 }
2901
defaultTextInputEventHandler(TextEvent * event)2902 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
2903 {
2904 if (m_frame->editor()->handleTextEvent(event))
2905 event->setDefaultHandled();
2906 }
2907
2908 #if PLATFORM(QT) || PLATFORM(ANDROID)
2909 // Qt handles the space event in platform-specific WebKit code.
2910 // Eventually it would be good to eliminate that and use the code here instead.
defaultSpaceEventHandler(KeyboardEvent *)2911 void EventHandler::defaultSpaceEventHandler(KeyboardEvent*)
2912 {
2913 }
2914 #else
2915
defaultSpaceEventHandler(KeyboardEvent * event)2916 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
2917 {
2918 ASSERT(event->type() == eventNames().keypressEvent);
2919
2920 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
2921 return;
2922
2923 ScrollLogicalDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
2924 if (logicalScrollOverflow(direction, ScrollByPage)) {
2925 event->setDefaultHandled();
2926 return;
2927 }
2928
2929 FrameView* view = m_frame->view();
2930 if (!view)
2931 return;
2932
2933 if (view->logicalScroll(direction, ScrollByPage))
2934 event->setDefaultHandled();
2935 }
2936
2937 #endif
2938
defaultBackspaceEventHandler(KeyboardEvent * event)2939 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
2940 {
2941 ASSERT(event->type() == eventNames().keydownEvent);
2942
2943 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
2944 return;
2945
2946 Page* page = m_frame->page();
2947 if (!page)
2948 return;
2949
2950 bool handledEvent = false;
2951
2952 if (event->shiftKey())
2953 handledEvent = page->goForward();
2954 else
2955 handledEvent = page->goBack();
2956
2957 if (handledEvent)
2958 event->setDefaultHandled();
2959 }
2960
2961
defaultArrowEventHandler(FocusDirection focusDirection,KeyboardEvent * event)2962 void EventHandler::defaultArrowEventHandler(FocusDirection focusDirection, KeyboardEvent* event)
2963 {
2964 ASSERT(event->type() == eventNames().keydownEvent);
2965
2966 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
2967 return;
2968
2969 Page* page = m_frame->page();
2970 if (!page)
2971 return;
2972
2973 if (!isSpatialNavigationEnabled(m_frame))
2974 return;
2975
2976 // Arrows and other possible directional navigation keys can be used in design
2977 // mode editing.
2978 if (m_frame->document()->inDesignMode())
2979 return;
2980
2981 if (page->focusController()->advanceFocus(focusDirection, event))
2982 event->setDefaultHandled();
2983 }
2984
defaultTabEventHandler(KeyboardEvent * event)2985 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
2986 {
2987 ASSERT(event->type() == eventNames().keydownEvent);
2988
2989 // We should only advance focus on tabs if no special modifier keys are held down.
2990 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
2991 return;
2992
2993 Page* page = m_frame->page();
2994 if (!page)
2995 return;
2996 if (!page->tabKeyCyclesThroughElements())
2997 return;
2998
2999 FocusDirection focusDirection = event->shiftKey() ? FocusDirectionBackward : FocusDirectionForward;
3000
3001 // Tabs can be used in design mode editing.
3002 if (m_frame->document()->inDesignMode())
3003 return;
3004
3005 if (page->focusController()->advanceFocus(focusDirection, event))
3006 event->setDefaultHandled();
3007 }
3008
capsLockStateMayHaveChanged()3009 void EventHandler::capsLockStateMayHaveChanged()
3010 {
3011 Document* d = m_frame->document();
3012 if (Node* node = d->focusedNode()) {
3013 if (RenderObject* r = node->renderer()) {
3014 if (r->isTextField())
3015 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3016 }
3017 }
3018 }
3019
sendResizeEvent()3020 void EventHandler::sendResizeEvent()
3021 {
3022 m_frame->document()->enqueueWindowEvent(Event::create(eventNames().resizeEvent, false, false));
3023 }
3024
sendScrollEvent()3025 void EventHandler::sendScrollEvent()
3026 {
3027 setFrameWasScrolledByUser();
3028 if (m_frame->view() && m_frame->document())
3029 m_frame->document()->eventQueue()->enqueueOrDispatchScrollEvent(m_frame->document(), EventQueue::ScrollEventDocumentTarget);
3030 }
3031
setFrameWasScrolledByUser()3032 void EventHandler::setFrameWasScrolledByUser()
3033 {
3034 FrameView* v = m_frame->view();
3035 if (v)
3036 v->setWasScrolledByUser(true);
3037 }
3038
passMousePressEventToScrollbar(MouseEventWithHitTestResults & mev,Scrollbar * scrollbar)3039 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev, Scrollbar* scrollbar)
3040 {
3041 if (!scrollbar || !scrollbar->enabled())
3042 return false;
3043 setFrameWasScrolledByUser();
3044 return scrollbar->mouseDown(mev.event());
3045 }
3046
3047 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3048 // last to scrollbar if setLast is true; else set last to 0.
updateLastScrollbarUnderMouse(Scrollbar * scrollbar,bool setLast)3049 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3050 {
3051 if (m_lastScrollbarUnderMouse != scrollbar) {
3052 // Send mouse exited to the old scrollbar.
3053 if (m_lastScrollbarUnderMouse)
3054 m_lastScrollbarUnderMouse->mouseExited();
3055 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3056 }
3057 }
3058
3059 #if ENABLE(TOUCH_EVENTS)
3060
eventNameForTouchPointState(PlatformTouchPoint::State state)3061 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3062 {
3063 switch (state) {
3064 case PlatformTouchPoint::TouchReleased:
3065 return eventNames().touchendEvent;
3066 case PlatformTouchPoint::TouchCancelled:
3067 return eventNames().touchcancelEvent;
3068 case PlatformTouchPoint::TouchPressed:
3069 return eventNames().touchstartEvent;
3070 case PlatformTouchPoint::TouchMoved:
3071 return eventNames().touchmoveEvent;
3072 default:
3073 ASSERT_NOT_REACHED();
3074 return emptyAtom;
3075 }
3076 }
3077
handleTouchEvent(const PlatformTouchEvent & event)3078 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3079 {
3080 // First build up the lists to use for the 'touches', 'targetTouches' and 'changedTouches' attributes
3081 // in the JS event. See http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
3082 // for an overview of how these lists fit together.
3083
3084 // Holds the complete set of touches on the screen and will be used as the 'touches' list in the JS event.
3085 RefPtr<TouchList> touches = TouchList::create();
3086
3087 // A different view on the 'touches' list above, filtered and grouped by event target. Used for the
3088 // 'targetTouches' list in the JS event.
3089 typedef HashMap<EventTarget*, RefPtr<TouchList> > TargetTouchesMap;
3090 TargetTouchesMap touchesByTarget;
3091
3092 // Array of touches per state, used to assemble the 'changedTouches' list in the JS event.
3093 typedef HashSet<RefPtr<EventTarget> > EventTargetSet;
3094 struct {
3095 // The touches corresponding to the particular change state this struct instance represents.
3096 RefPtr<TouchList> m_touches;
3097 // Set of targets involved in m_touches.
3098 EventTargetSet m_targets;
3099 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3100
3101 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3102
3103 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
3104
3105 for (unsigned i = 0; i < points.size(); ++i) {
3106 const PlatformTouchPoint& point = points[i];
3107 PlatformTouchPoint::State pointState = point.state();
3108 IntPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos());
3109
3110 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ReadOnly;
3111 // The HitTestRequest types used for mouse events map quite adequately
3112 // to touch events. Note that in addition to meaning that the hit test
3113 // should affect the active state of the current node if necessary,
3114 // HitTestRequest::Active signifies that the hit test is taking place
3115 // with the mouse (or finger in this case) being pressed.
3116 switch (pointState) {
3117 case PlatformTouchPoint::TouchPressed:
3118 hitType = HitTestRequest::Active;
3119 break;
3120 case PlatformTouchPoint::TouchMoved:
3121 hitType = HitTestRequest::Active | HitTestRequest::MouseMove | HitTestRequest::ReadOnly;
3122 break;
3123 case PlatformTouchPoint::TouchReleased:
3124 case PlatformTouchPoint::TouchCancelled:
3125 hitType = HitTestRequest::MouseUp;
3126 break;
3127 default:
3128 break;
3129 }
3130 #if PLATFORM(ANDROID)
3131 Node* node = 0;
3132 if (m_capturingTouchEventsNode)
3133 node = m_capturingTouchEventsNode.get();
3134 else {
3135 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3136 node = result.innerNode();
3137 ASSERT(node);
3138
3139 // Touch events should not go to text nodes
3140 if (node->isTextNode())
3141 node = node->parentNode();
3142 }
3143 #else
3144 HitTestResult result = hitTestResultAtPoint(pagePoint, /*allowShadowContent*/ false, false, DontHitTestScrollbars, hitType);
3145 Node* node = result.innerNode();
3146 ASSERT(node);
3147
3148 // Touch events should not go to text nodes
3149 if (node->isTextNode())
3150 node = node->parentNode();
3151 #endif
3152
3153
3154 Document* doc = node->document();
3155 if (!doc)
3156 continue;
3157 if (!doc->hasListenerType(Document::TOUCH_LISTENER))
3158 continue;
3159
3160 if (m_frame != doc->frame()) {
3161 // pagePoint should always be relative to the target elements containing frame.
3162 pagePoint = documentPointForWindowPoint(doc->frame(), point.pos());
3163 }
3164
3165 int adjustedPageX = lroundf(pagePoint.x() / m_frame->pageZoomFactor());
3166 int adjustedPageY = lroundf(pagePoint.y() / m_frame->pageZoomFactor());
3167
3168 // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
3169 unsigned touchPointTargetKey = point.id() + 1;
3170 RefPtr<EventTarget> touchTarget;
3171 #if PLATFORM(ANDROID)
3172 if (m_capturingTouchEventsNode)
3173 touchTarget = node;
3174 else {
3175 #endif
3176 if (pointState == PlatformTouchPoint::TouchPressed) {
3177 m_originatingTouchPointTargets.set(touchPointTargetKey, node);
3178 touchTarget = node;
3179 } else if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3180 // The target should be the original target for this touch, so get it from the hashmap. As it's a release or cancel
3181 // we also remove it from the map.
3182 touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
3183 } else
3184 touchTarget = m_originatingTouchPointTargets.get(touchPointTargetKey);
3185 #if PLATFORM(ANDROID)
3186 }
3187 #endif
3188 if (!touchTarget.get())
3189 continue;
3190
3191 RefPtr<Touch> touch = Touch::create(doc->frame(), touchTarget.get(), point.id(),
3192 point.screenPos().x(), point.screenPos().y(),
3193 adjustedPageX, adjustedPageY);
3194
3195 // Ensure this target's touch list exists, even if it ends up empty, so it can always be passed to TouchEvent::Create below.
3196 TargetTouchesMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3197 if (targetTouchesIterator == touchesByTarget.end())
3198 targetTouchesIterator = touchesByTarget.set(touchTarget.get(), TouchList::create()).first;
3199
3200 // touches and targetTouches should only contain information about touches still on the screen, so if this point is
3201 // released or cancelled it will only appear in the changedTouches list.
3202 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3203 touches->append(touch);
3204 targetTouchesIterator->second->append(touch);
3205 }
3206
3207 // Now build up the correct list for changedTouches.
3208 // Note that any touches that are in the TouchStationary state (e.g. if
3209 // the user had several points touched but did not move them all) should
3210 // never be in the changedTouches list so we do not handle them explicitly here.
3211 // See https://bugs.webkit.org/show_bug.cgi?id=37609 for further discussion
3212 // about the TouchStationary state.
3213 if (pointState != PlatformTouchPoint::TouchStationary) {
3214 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3215 if (!changedTouches[pointState].m_touches)
3216 changedTouches[pointState].m_touches = TouchList::create();
3217 changedTouches[pointState].m_touches->append(touch);
3218 changedTouches[pointState].m_targets.add(touchTarget);
3219 }
3220 }
3221 m_touchPressed = touches->length() > 0;
3222
3223 // Now iterate the changedTouches list and m_targets within it, sending events to the tagets as required.
3224 bool defaultPrevented = false;
3225 RefPtr<TouchList> emptyList = TouchList::create();
3226 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3227 if (!changedTouches[state].m_touches)
3228 continue;
3229
3230 // When sending a touch cancel event, use empty touches and targetTouches lists.
3231 bool isTouchCancelEvent = (state == PlatformTouchPoint::TouchCancelled);
3232 RefPtr<TouchList>& effectiveTouches(isTouchCancelEvent ? emptyList : touches);
3233 #if PLATFORM(ANDROID)
3234 AtomicString stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3235 if (event.type() == TouchLongPress)
3236 stateName = eventNames().touchlongpressEvent;
3237 else if (event.type() == TouchDoubleTap)
3238 stateName = eventNames().touchdoubletapEvent;
3239 #else
3240 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3241 #endif
3242 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3243
3244 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3245 EventTarget* touchEventTarget = it->get();
3246 RefPtr<TouchList> targetTouches(isTouchCancelEvent ? emptyList : touchesByTarget.get(touchEventTarget));
3247 ASSERT(targetTouches);
3248
3249 RefPtr<TouchEvent> touchEvent =
3250 TouchEvent::create(effectiveTouches.get(), targetTouches.get(), changedTouches[state].m_touches.get(),
3251 stateName, touchEventTarget->toNode()->document()->defaultView(),
3252 0, 0, 0, 0, event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey());
3253 ExceptionCode ec = 0;
3254 touchEventTarget->dispatchEvent(touchEvent.get(), ec);
3255 defaultPrevented |= touchEvent->defaultPrevented();
3256 }
3257 }
3258
3259 #if ENABLE(GESTURE_RECOGNIZER)
3260 if (m_gestureRecognizer)
3261 m_gestureRecognizer->processTouchEventForGesture(event, this, defaultPrevented);
3262 #endif
3263
3264 return defaultPrevented;
3265 }
3266 #endif
3267
3268 }
3269