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 * Copyright (C) 2012 Digia Plc. and/or its subsidiary(-ies)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "config.h"
29 #include "core/page/EventHandler.h"
30
31 #include "bindings/v8/ExceptionStatePlaceholder.h"
32 #include "core/HTMLNames.h"
33 #include "core/SVGNames.h"
34 #include "core/clipboard/Clipboard.h"
35 #include "core/clipboard/DataObject.h"
36 #include "core/dom/Document.h"
37 #include "core/dom/DocumentMarkerController.h"
38 #include "core/dom/FullscreenElementStack.h"
39 #include "core/dom/NodeRenderingTraversal.h"
40 #include "core/dom/TouchList.h"
41 #include "core/dom/shadow/ShadowRoot.h"
42 #include "core/editing/Editor.h"
43 #include "core/editing/FrameSelection.h"
44 #include "core/editing/TextIterator.h"
45 #include "core/editing/htmlediting.h"
46 #include "core/events/DOMWindowEventQueue.h"
47 #include "core/events/EventPath.h"
48 #include "core/events/KeyboardEvent.h"
49 #include "core/events/MouseEvent.h"
50 #include "core/events/TextEvent.h"
51 #include "core/events/TouchEvent.h"
52 #include "core/events/WheelEvent.h"
53 #include "core/fetch/ImageResource.h"
54 #include "core/frame/FrameView.h"
55 #include "core/frame/LocalFrame.h"
56 #include "core/html/HTMLDialogElement.h"
57 #include "core/html/HTMLFrameElementBase.h"
58 #include "core/html/HTMLFrameSetElement.h"
59 #include "core/html/HTMLInputElement.h"
60 #include "core/loader/FrameLoader.h"
61 #include "core/loader/FrameLoaderClient.h"
62 #include "core/page/AutoscrollController.h"
63 #include "core/page/BackForwardClient.h"
64 #include "core/page/Chrome.h"
65 #include "core/page/ChromeClient.h"
66 #include "core/page/DragController.h"
67 #include "core/page/DragState.h"
68 #include "core/page/EditorClient.h"
69 #include "core/page/FocusController.h"
70 #include "core/page/FrameTree.h"
71 #include "core/inspector/InspectorController.h"
72 #include "core/page/MouseEventWithHitTestResults.h"
73 #include "core/page/Page.h"
74 #include "core/frame/Settings.h"
75 #include "core/page/SpatialNavigation.h"
76 #include "core/page/TouchAdjustment.h"
77 #include "core/rendering/HitTestRequest.h"
78 #include "core/rendering/HitTestResult.h"
79 #include "core/rendering/RenderFlowThread.h"
80 #include "core/rendering/RenderLayer.h"
81 #include "core/rendering/RenderTextControlSingleLine.h"
82 #include "core/rendering/RenderView.h"
83 #include "core/rendering/RenderWidget.h"
84 #include "core/rendering/style/RenderStyle.h"
85 #include "core/svg/SVGDocumentExtensions.h"
86 #include "platform/PlatformGestureEvent.h"
87 #include "platform/PlatformKeyboardEvent.h"
88 #include "platform/PlatformTouchEvent.h"
89 #include "platform/PlatformWheelEvent.h"
90 #include "platform/RuntimeEnabledFeatures.h"
91 #include "platform/TraceEvent.h"
92 #include "platform/WindowsKeyboardCodes.h"
93 #include "platform/geometry/FloatPoint.h"
94 #include "platform/graphics/Image.h"
95 #include "platform/heap/Handle.h"
96 #include "platform/scroll/ScrollAnimator.h"
97 #include "platform/scroll/Scrollbar.h"
98 #include "wtf/Assertions.h"
99 #include "wtf/CurrentTime.h"
100 #include "wtf/StdLibExtras.h"
101 #include "wtf/TemporaryChange.h"
102
103 namespace WebCore {
104
105 using namespace HTMLNames;
106
107 // The link drag hysteresis is much larger than the others because there
108 // needs to be enough space to cancel the link press without starting a link drag,
109 // and because dragging links is rare.
110 static const int LinkDragHysteresis = 40;
111 static const int ImageDragHysteresis = 5;
112 static const int TextDragHysteresis = 3;
113 static const int GeneralDragHysteresis = 3;
114
115 // The amount of time to wait before sending a fake mouse event, triggered
116 // during a scroll. The short interval is used if the content responds to the mouse events quickly enough,
117 // otherwise the long interval is used.
118 static const double fakeMouseMoveShortInterval = 0.1;
119 static const double fakeMouseMoveLongInterval = 0.250;
120
121 // The amount of time to wait for a cursor update on style and layout changes
122 // Set to 50Hz, no need to be faster than common screen refresh rate
123 static const double cursorUpdateInterval = 0.02;
124
125 static const int maximumCursorSize = 128;
126
127 // It's pretty unlikely that a scale of less than one would ever be used. But all we really
128 // need to ensure here is that the scale isn't so small that integer overflow can occur when
129 // dividing cursor sizes (limited above) by the scale.
130 static const double minimumCursorScale = 0.001;
131
132 // The minimum amount of time an element stays active after a ShowPress
133 // This is roughly 9 frames, which should be long enough to be noticeable.
134 static const double minimumActiveInterval = 0.15;
135
136 #if OS(MACOSX)
137 static const double TextDragDelay = 0.15;
138 #else
139 static const double TextDragDelay = 0.0;
140 #endif
141
142 enum NoCursorChangeType { NoCursorChange };
143
144 class OptionalCursor {
145 public:
OptionalCursor(NoCursorChangeType)146 OptionalCursor(NoCursorChangeType) : m_isCursorChange(false) { }
OptionalCursor(const Cursor & cursor)147 OptionalCursor(const Cursor& cursor) : m_isCursorChange(true), m_cursor(cursor) { }
148
isCursorChange() const149 bool isCursorChange() const { return m_isCursorChange; }
cursor() const150 const Cursor& cursor() const { ASSERT(m_isCursorChange); return m_cursor; }
151
152 private:
153 bool m_isCursorChange;
154 Cursor m_cursor;
155 };
156
157 class MaximumDurationTracker {
158 public:
MaximumDurationTracker(double * maxDuration)159 explicit MaximumDurationTracker(double *maxDuration)
160 : m_maxDuration(maxDuration)
161 , m_start(monotonicallyIncreasingTime())
162 {
163 }
164
~MaximumDurationTracker()165 ~MaximumDurationTracker()
166 {
167 *m_maxDuration = max(*m_maxDuration, monotonicallyIncreasingTime() - m_start);
168 }
169
170 private:
171 double* m_maxDuration;
172 double m_start;
173 };
174
wheelGranularityToScrollGranularity(unsigned deltaMode)175 static inline ScrollGranularity wheelGranularityToScrollGranularity(unsigned deltaMode)
176 {
177 switch (deltaMode) {
178 case WheelEvent::DOM_DELTA_PAGE:
179 return ScrollByPage;
180 case WheelEvent::DOM_DELTA_LINE:
181 return ScrollByLine;
182 case WheelEvent::DOM_DELTA_PIXEL:
183 return ScrollByPixel;
184 default:
185 return ScrollByPixel;
186 }
187 }
188
189 // Refetch the event target node if it is removed or currently is the shadow node inside an <input> element.
190 // If a mouse event handler changes the input element type to one that has a widget associated,
191 // we'd like to EventHandler::handleMousePressEvent to pass the event to the widget and thus the
192 // event target node can't still be the shadow node.
shouldRefetchEventTarget(const MouseEventWithHitTestResults & mev)193 static inline bool shouldRefetchEventTarget(const MouseEventWithHitTestResults& mev)
194 {
195 Node* targetNode = mev.targetNode();
196 if (!targetNode || !targetNode->parentNode())
197 return true;
198 return targetNode->isShadowRoot() && isHTMLInputElement(*toShadowRoot(targetNode)->host());
199 }
200
EventHandler(LocalFrame * frame)201 EventHandler::EventHandler(LocalFrame* frame)
202 : m_frame(frame)
203 , m_mousePressed(false)
204 , m_capturesDragging(false)
205 , m_mouseDownMayStartSelect(false)
206 , m_mouseDownMayStartDrag(false)
207 , m_mouseDownWasSingleClickInSelection(false)
208 , m_selectionInitiationState(HaveNotStartedSelection)
209 , m_hoverTimer(this, &EventHandler::hoverTimerFired)
210 , m_cursorUpdateTimer(this, &EventHandler::cursorUpdateTimerFired)
211 , m_mouseDownMayStartAutoscroll(false)
212 , m_mouseDownWasInSubframe(false)
213 , m_fakeMouseMoveEventTimer(this, &EventHandler::fakeMouseMoveEventTimerFired)
214 , m_svgPan(false)
215 , m_resizeScrollableArea(0)
216 , m_eventHandlerWillResetCapturingMouseEventsNode(0)
217 , m_clickCount(0)
218 , m_shouldOnlyFireDragOverEvent(false)
219 , m_mousePositionIsUnknown(true)
220 , m_mouseDownTimestamp(0)
221 , m_widgetIsLatched(false)
222 , m_touchPressed(false)
223 , m_scrollGestureHandlingNode(nullptr)
224 , m_lastHitTestResultOverWidget(false)
225 , m_maxMouseMovedDuration(0)
226 , m_baseEventType(PlatformEvent::NoType)
227 , m_didStartDrag(false)
228 , m_longTapShouldInvokeContextMenu(false)
229 , m_activeIntervalTimer(this, &EventHandler::activeIntervalTimerFired)
230 , m_lastShowPressTimestamp(0)
231 {
232 }
233
~EventHandler()234 EventHandler::~EventHandler()
235 {
236 ASSERT(!m_fakeMouseMoveEventTimer.isActive());
237 }
238
trace(Visitor * visitor)239 void EventHandler::trace(Visitor* visitor)
240 {
241 visitor->trace(m_mousePressNode);
242 visitor->trace(m_capturingMouseEventsNode);
243 visitor->trace(m_nodeUnderMouse);
244 visitor->trace(m_lastNodeUnderMouse);
245 visitor->trace(m_clickNode);
246 visitor->trace(m_dragTarget);
247 visitor->trace(m_frameSetBeingResized);
248 visitor->trace(m_latchedWheelEventNode);
249 visitor->trace(m_previousWheelScrolledNode);
250 visitor->trace(m_targetForTouchID);
251 visitor->trace(m_touchSequenceDocument);
252 visitor->trace(m_scrollGestureHandlingNode);
253 visitor->trace(m_previousGestureScrolledNode);
254 visitor->trace(m_lastDeferredTapElement);
255 }
256
dragState()257 DragState& EventHandler::dragState()
258 {
259 #if ENABLE(OILPAN)
260 DEFINE_STATIC_LOCAL(Persistent<DragState>, state, (new DragState()));
261 return *state;
262 #else
263 DEFINE_STATIC_LOCAL(DragState, state, ());
264 return state;
265 #endif
266 }
267
clear()268 void EventHandler::clear()
269 {
270 m_hoverTimer.stop();
271 m_cursorUpdateTimer.stop();
272 m_fakeMouseMoveEventTimer.stop();
273 m_activeIntervalTimer.stop();
274 m_resizeScrollableArea = 0;
275 m_nodeUnderMouse = nullptr;
276 m_lastNodeUnderMouse = nullptr;
277 m_lastMouseMoveEventSubframe = nullptr;
278 m_lastScrollbarUnderMouse = nullptr;
279 m_clickCount = 0;
280 m_clickNode = nullptr;
281 m_frameSetBeingResized = nullptr;
282 m_dragTarget = nullptr;
283 m_shouldOnlyFireDragOverEvent = false;
284 m_mousePositionIsUnknown = true;
285 m_lastKnownMousePosition = IntPoint();
286 m_lastKnownMouseGlobalPosition = IntPoint();
287 m_lastMouseDownUserGestureToken.clear();
288 m_mousePressNode = nullptr;
289 m_mousePressed = false;
290 m_capturesDragging = false;
291 m_capturingMouseEventsNode = nullptr;
292 m_latchedWheelEventNode = nullptr;
293 m_previousWheelScrolledNode = nullptr;
294 m_targetForTouchID.clear();
295 m_touchSequenceDocument.clear();
296 m_touchSequenceUserGestureToken.clear();
297 m_scrollGestureHandlingNode = nullptr;
298 m_lastHitTestResultOverWidget = false;
299 m_previousGestureScrolledNode = nullptr;
300 m_scrollbarHandlingScrollGesture = nullptr;
301 m_maxMouseMovedDuration = 0;
302 m_baseEventType = PlatformEvent::NoType;
303 m_didStartDrag = false;
304 m_touchPressed = false;
305 m_mouseDownMayStartSelect = false;
306 m_mouseDownMayStartDrag = false;
307 m_lastShowPressTimestamp = 0;
308 m_lastDeferredTapElement = nullptr;
309 }
310
nodeWillBeRemoved(Node & nodeToBeRemoved)311 void EventHandler::nodeWillBeRemoved(Node& nodeToBeRemoved)
312 {
313 if (!nodeToBeRemoved.containsIncludingShadowDOM(m_clickNode.get()))
314 return;
315 if (nodeToBeRemoved.isInShadowTree()) {
316 m_clickNode = nodeToBeRemoved.parentOrShadowHostNode();
317 } else {
318 // We don't dispatch click events if the mousedown node is removed
319 // before a mouseup event. It is compatible with IE and Firefox.
320 m_clickNode = nullptr;
321 }
322 }
323
setSelectionIfNeeded(FrameSelection & selection,const VisibleSelection & newSelection)324 static void setSelectionIfNeeded(FrameSelection& selection, const VisibleSelection& newSelection)
325 {
326 if (selection.selection() != newSelection)
327 selection.setSelection(newSelection);
328 }
329
dispatchSelectStart(Node * node)330 static inline bool dispatchSelectStart(Node* node)
331 {
332 if (!node || !node->renderer())
333 return true;
334
335 return node->dispatchEvent(Event::createCancelableBubble(EventTypeNames::selectstart));
336 }
337
expandSelectionToRespectUserSelectAll(Node * targetNode,const VisibleSelection & selection)338 static VisibleSelection expandSelectionToRespectUserSelectAll(Node* targetNode, const VisibleSelection& selection)
339 {
340 Node* rootUserSelectAll = Position::rootUserSelectAllForNode(targetNode);
341 if (!rootUserSelectAll)
342 return selection;
343
344 VisibleSelection newSelection(selection);
345 newSelection.setBase(positionBeforeNode(rootUserSelectAll).upstream(CanCrossEditingBoundary));
346 newSelection.setExtent(positionAfterNode(rootUserSelectAll).downstream(CanCrossEditingBoundary));
347
348 return newSelection;
349 }
350
updateSelectionForMouseDownDispatchingSelectStart(Node * targetNode,const VisibleSelection & selection,TextGranularity granularity)351 bool EventHandler::updateSelectionForMouseDownDispatchingSelectStart(Node* targetNode, const VisibleSelection& selection, TextGranularity granularity)
352 {
353 if (Position::nodeIsUserSelectNone(targetNode))
354 return false;
355
356 if (!dispatchSelectStart(targetNode))
357 return false;
358
359 if (selection.isRange())
360 m_selectionInitiationState = ExtendedSelection;
361 else {
362 granularity = CharacterGranularity;
363 m_selectionInitiationState = PlacedCaret;
364 }
365
366 m_frame->selection().setNonDirectionalSelectionIfNeeded(selection, granularity);
367
368 return true;
369 }
370
selectClosestWordFromHitTestResult(const HitTestResult & result,AppendTrailingWhitespace appendTrailingWhitespace)371 void EventHandler::selectClosestWordFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
372 {
373 Node* innerNode = result.targetNode();
374 VisibleSelection newSelection;
375
376 if (innerNode && innerNode->renderer()) {
377 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
378 if (pos.isNotNull()) {
379 newSelection = VisibleSelection(pos);
380 newSelection.expandUsingGranularity(WordGranularity);
381 }
382
383 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
384 newSelection.appendTrailingWhitespace();
385
386 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
387 }
388 }
389
selectClosestMisspellingFromHitTestResult(const HitTestResult & result,AppendTrailingWhitespace appendTrailingWhitespace)390 void EventHandler::selectClosestMisspellingFromHitTestResult(const HitTestResult& result, AppendTrailingWhitespace appendTrailingWhitespace)
391 {
392 Node* innerNode = result.targetNode();
393 VisibleSelection newSelection;
394
395 if (innerNode && innerNode->renderer()) {
396 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
397 Position start = pos.deepEquivalent();
398 Position end = pos.deepEquivalent();
399 if (pos.isNotNull()) {
400 WillBeHeapVector<DocumentMarker*> markers = innerNode->document().markers().markersInRange(makeRange(pos, pos).get(), DocumentMarker::MisspellingMarkers());
401 if (markers.size() == 1) {
402 start.moveToOffset(markers[0]->startOffset());
403 end.moveToOffset(markers[0]->endOffset());
404 newSelection = VisibleSelection(start, end);
405 }
406 }
407
408 if (appendTrailingWhitespace == ShouldAppendTrailingWhitespace && newSelection.isRange())
409 newSelection.appendTrailingWhitespace();
410
411 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
412 }
413 }
414
selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults & result)415 void EventHandler::selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults& result)
416 {
417 if (m_mouseDownMayStartSelect) {
418 selectClosestWordFromHitTestResult(result.hitTestResult(),
419 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
420 }
421 }
422
selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults & result)423 void EventHandler::selectClosestMisspellingFromMouseEvent(const MouseEventWithHitTestResults& result)
424 {
425 if (m_mouseDownMayStartSelect) {
426 selectClosestMisspellingFromHitTestResult(result.hitTestResult(),
427 (result.event().clickCount() == 2 && m_frame->editor().isSelectTrailingWhitespaceEnabled()) ? ShouldAppendTrailingWhitespace : DontAppendTrailingWhitespace);
428 }
429 }
430
selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults & result)431 void EventHandler::selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults& result)
432 {
433 if (!result.hitTestResult().isLiveLink())
434 return selectClosestWordFromMouseEvent(result);
435
436 Node* innerNode = result.targetNode();
437
438 if (innerNode && innerNode->renderer() && m_mouseDownMayStartSelect) {
439 VisibleSelection newSelection;
440 Element* URLElement = result.hitTestResult().URLElement();
441 VisiblePosition pos(innerNode->renderer()->positionForPoint(result.localPoint()));
442 if (pos.isNotNull() && pos.deepEquivalent().deprecatedNode()->isDescendantOf(URLElement))
443 newSelection = VisibleSelection::selectionFromContentsOfNode(URLElement);
444
445 updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), WordGranularity);
446 }
447 }
448
handleMousePressEventDoubleClick(const MouseEventWithHitTestResults & event)449 bool EventHandler::handleMousePressEventDoubleClick(const MouseEventWithHitTestResults& event)
450 {
451 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventDoubleClick");
452
453 if (event.event().button() != LeftButton)
454 return false;
455
456 if (m_frame->selection().isRange()) {
457 // A double-click when range is already selected
458 // should not change the selection. So, do not call
459 // selectClosestWordFromMouseEvent, but do set
460 // m_beganSelectingText to prevent handleMouseReleaseEvent
461 // from setting caret selection.
462 m_selectionInitiationState = ExtendedSelection;
463 } else {
464 selectClosestWordFromMouseEvent(event);
465 }
466 return true;
467 }
468
handleMousePressEventTripleClick(const MouseEventWithHitTestResults & event)469 bool EventHandler::handleMousePressEventTripleClick(const MouseEventWithHitTestResults& event)
470 {
471 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventTripleClick");
472
473 if (event.event().button() != LeftButton)
474 return false;
475
476 Node* innerNode = event.targetNode();
477 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
478 return false;
479
480 VisibleSelection newSelection;
481 VisiblePosition pos(innerNode->renderer()->positionForPoint(event.localPoint()));
482 if (pos.isNotNull()) {
483 newSelection = VisibleSelection(pos);
484 newSelection.expandUsingGranularity(ParagraphGranularity);
485 }
486
487 return updateSelectionForMouseDownDispatchingSelectStart(innerNode, expandSelectionToRespectUserSelectAll(innerNode, newSelection), ParagraphGranularity);
488 }
489
textDistance(const Position & start,const Position & end)490 static int textDistance(const Position& start, const Position& end)
491 {
492 RefPtrWillBeRawPtr<Range> range = Range::create(*start.document(), start, end);
493 return TextIterator::rangeLength(range.get(), true);
494 }
495
handleMousePressEventSingleClick(const MouseEventWithHitTestResults & event)496 bool EventHandler::handleMousePressEventSingleClick(const MouseEventWithHitTestResults& event)
497 {
498 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEventSingleClick");
499
500 m_frame->document()->updateLayoutIgnorePendingStylesheets();
501 Node* innerNode = event.targetNode();
502 if (!(innerNode && innerNode->renderer() && m_mouseDownMayStartSelect))
503 return false;
504
505 // Extend the selection if the Shift key is down, unless the click is in a link.
506 bool extendSelection = event.event().shiftKey() && !event.isOverLink();
507
508 // Don't restart the selection when the mouse is pressed on an
509 // existing selection so we can allow for text dragging.
510 if (FrameView* view = m_frame->view()) {
511 LayoutPoint vPoint = view->windowToContents(event.event().position());
512 if (!extendSelection && m_frame->selection().contains(vPoint)) {
513 m_mouseDownWasSingleClickInSelection = true;
514 return false;
515 }
516 }
517
518 VisiblePosition visiblePos(innerNode->renderer()->positionForPoint(event.localPoint()));
519 if (visiblePos.isNull())
520 visiblePos = VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
521 Position pos = visiblePos.deepEquivalent();
522
523 VisibleSelection newSelection = m_frame->selection().selection();
524 TextGranularity granularity = CharacterGranularity;
525
526 if (extendSelection && newSelection.isCaretOrRange()) {
527 VisibleSelection selectionInUserSelectAll(expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(VisiblePosition(pos))));
528 if (selectionInUserSelectAll.isRange()) {
529 if (comparePositions(selectionInUserSelectAll.start(), newSelection.start()) < 0)
530 pos = selectionInUserSelectAll.start();
531 else if (comparePositions(newSelection.end(), selectionInUserSelectAll.end()) < 0)
532 pos = selectionInUserSelectAll.end();
533 }
534
535 if (!m_frame->editor().behavior().shouldConsiderSelectionAsDirectional()) {
536 if (pos.isNotNull()) {
537 // See <rdar://problem/3668157> REGRESSION (Mail): shift-click deselects when selection
538 // was created right-to-left
539 Position start = newSelection.start();
540 Position end = newSelection.end();
541 int distanceToStart = textDistance(start, pos);
542 int distanceToEnd = textDistance(pos, end);
543 if (distanceToStart <= distanceToEnd)
544 newSelection = VisibleSelection(end, pos);
545 else
546 newSelection = VisibleSelection(start, pos);
547 }
548 } else
549 newSelection.setExtent(pos);
550
551 if (m_frame->selection().granularity() != CharacterGranularity) {
552 granularity = m_frame->selection().granularity();
553 newSelection.expandUsingGranularity(m_frame->selection().granularity());
554 }
555 } else {
556 newSelection = expandSelectionToRespectUserSelectAll(innerNode, VisibleSelection(visiblePos));
557 }
558
559 // Updating the selection is considered side-effect of the event and so it doesn't impact the handled state.
560 updateSelectionForMouseDownDispatchingSelectStart(innerNode, newSelection, granularity);
561 return false;
562 }
563
canMouseDownStartSelect(Node * node)564 static inline bool canMouseDownStartSelect(Node* node)
565 {
566 if (!node || !node->renderer())
567 return true;
568
569 if (!node->canStartSelection())
570 return false;
571
572 return true;
573 }
574
handleMousePressEvent(const MouseEventWithHitTestResults & event)575 bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& event)
576 {
577 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
578
579 // Reset drag state.
580 dragState().m_dragSrc = nullptr;
581
582 cancelFakeMouseMoveEvent();
583
584 m_frame->document()->updateLayoutIgnorePendingStylesheets();
585
586 if (ScrollView* scrollView = m_frame->view()) {
587 if (scrollView->isPointInScrollbarCorner(event.event().position()))
588 return false;
589 }
590
591 bool singleClick = event.event().clickCount() <= 1;
592
593 // If we got the event back, that must mean it wasn't prevented,
594 // so it's allowed to start a drag or selection if it wasn't in a scrollbar.
595 m_mouseDownMayStartSelect = canMouseDownStartSelect(event.targetNode()) && !event.scrollbar();
596
597 m_mouseDownMayStartDrag = singleClick;
598
599 m_mouseDownWasSingleClickInSelection = false;
600
601 m_mouseDown = event.event();
602
603 if (event.isOverWidget() && passWidgetMouseDownEventToWidget(event))
604 return true;
605
606 if (m_frame->document()->isSVGDocument() && m_frame->document()->accessSVGExtensions().zoomAndPanEnabled()) {
607 if (event.event().shiftKey() && singleClick) {
608 m_svgPan = true;
609 m_frame->document()->accessSVGExtensions().startPan(m_frame->view()->windowToContents(event.event().position()));
610 return true;
611 }
612 }
613
614 // We don't do this at the start of mouse down handling,
615 // because we don't want to do it until we know we didn't hit a widget.
616 if (singleClick)
617 focusDocumentView();
618
619 Node* innerNode = event.targetNode();
620
621 m_mousePressNode = innerNode;
622 m_dragStartPos = event.event().position();
623
624 bool swallowEvent = false;
625 m_mousePressed = true;
626 m_selectionInitiationState = HaveNotStartedSelection;
627
628 if (event.event().clickCount() == 2)
629 swallowEvent = handleMousePressEventDoubleClick(event);
630 else if (event.event().clickCount() >= 3)
631 swallowEvent = handleMousePressEventTripleClick(event);
632 else
633 swallowEvent = handleMousePressEventSingleClick(event);
634
635 m_mouseDownMayStartAutoscroll = m_mouseDownMayStartSelect
636 || (m_mousePressNode && m_mousePressNode->renderBox() && m_mousePressNode->renderBox()->canBeProgramaticallyScrolled());
637
638 return swallowEvent;
639 }
640
handleMouseDraggedEvent(const MouseEventWithHitTestResults & event)641 bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& event)
642 {
643 TRACE_EVENT0("webkit", "EventHandler::handleMouseDraggedEvent");
644
645 if (!m_mousePressed)
646 return false;
647
648 if (handleDrag(event, ShouldCheckDragHysteresis))
649 return true;
650
651 Node* targetNode = event.targetNode();
652 if (event.event().button() != LeftButton || !targetNode)
653 return false;
654
655 RenderObject* renderer = targetNode->renderer();
656 if (!renderer) {
657 Node* parent = NodeRenderingTraversal::parent(targetNode);
658 if (!parent)
659 return false;
660
661 renderer = parent->renderer();
662 if (!renderer || !renderer->isListBox())
663 return false;
664 }
665
666 m_mouseDownMayStartDrag = false;
667
668 if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) {
669 if (AutoscrollController* controller = autoscrollController()) {
670 controller->startAutoscrollForSelection(renderer);
671 m_mouseDownMayStartAutoscroll = false;
672 }
673 }
674
675 if (m_selectionInitiationState != ExtendedSelection) {
676 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
677 HitTestResult result(m_mouseDownPos);
678 m_frame->document()->renderView()->hitTest(request, result);
679
680 updateSelectionForMouseDrag(result);
681 }
682 updateSelectionForMouseDrag(event.hitTestResult());
683 return true;
684 }
685
updateSelectionForMouseDrag()686 void EventHandler::updateSelectionForMouseDrag()
687 {
688 FrameView* view = m_frame->view();
689 if (!view)
690 return;
691 RenderView* renderer = m_frame->contentRenderer();
692 if (!renderer)
693 return;
694
695 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
696 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
697 renderer->hitTest(request, result);
698 updateSelectionForMouseDrag(result);
699 }
700
updateSelectionForMouseDrag(const HitTestResult & hitTestResult)701 void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResult)
702 {
703 if (!m_mouseDownMayStartSelect)
704 return;
705
706 Node* target = hitTestResult.targetNode();
707 if (!target)
708 return;
709
710 VisiblePosition targetPosition = m_frame->selection().selection().visiblePositionRespectingEditingBoundary(hitTestResult.localPoint(), target);
711 // Don't modify the selection if we're not on a node.
712 if (targetPosition.isNull())
713 return;
714
715 // Restart the selection if this is the first mouse move. This work is usually
716 // done in handleMousePressEvent, but not if the mouse press was on an existing selection.
717 VisibleSelection newSelection = m_frame->selection().selection();
718
719 // Special case to limit selection to the containing block for SVG text.
720 // FIXME: Isn't there a better non-SVG-specific way to do this?
721 if (Node* selectionBaseNode = newSelection.base().deprecatedNode())
722 if (RenderObject* selectionBaseRenderer = selectionBaseNode->renderer())
723 if (selectionBaseRenderer->isSVGText())
724 if (target->renderer()->containingBlock() != selectionBaseRenderer->containingBlock())
725 return;
726
727 if (m_selectionInitiationState == HaveNotStartedSelection && !dispatchSelectStart(target))
728 return;
729
730 if (m_selectionInitiationState != ExtendedSelection) {
731 // Always extend selection here because it's caused by a mouse drag
732 m_selectionInitiationState = ExtendedSelection;
733 newSelection = VisibleSelection(targetPosition);
734 }
735
736 if (RuntimeEnabledFeatures::userSelectAllEnabled()) {
737 Node* rootUserSelectAllForMousePressNode = Position::rootUserSelectAllForNode(m_mousePressNode.get());
738 if (rootUserSelectAllForMousePressNode && rootUserSelectAllForMousePressNode == Position::rootUserSelectAllForNode(target)) {
739 newSelection.setBase(positionBeforeNode(rootUserSelectAllForMousePressNode).upstream(CanCrossEditingBoundary));
740 newSelection.setExtent(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
741 } else {
742 // Reset base for user select all when base is inside user-select-all area and extent < base.
743 if (rootUserSelectAllForMousePressNode && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
744 newSelection.setBase(positionAfterNode(rootUserSelectAllForMousePressNode).downstream(CanCrossEditingBoundary));
745
746 Node* rootUserSelectAllForTarget = Position::rootUserSelectAllForNode(target);
747 if (rootUserSelectAllForTarget && m_mousePressNode->renderer() && comparePositions(target->renderer()->positionForPoint(hitTestResult.localPoint()), m_mousePressNode->renderer()->positionForPoint(m_dragStartPos)) < 0)
748 newSelection.setExtent(positionBeforeNode(rootUserSelectAllForTarget).upstream(CanCrossEditingBoundary));
749 else if (rootUserSelectAllForTarget && m_mousePressNode->renderer())
750 newSelection.setExtent(positionAfterNode(rootUserSelectAllForTarget).downstream(CanCrossEditingBoundary));
751 else
752 newSelection.setExtent(targetPosition);
753 }
754 } else {
755 newSelection.setExtent(targetPosition);
756 }
757
758 if (m_frame->selection().granularity() != CharacterGranularity)
759 newSelection.expandUsingGranularity(m_frame->selection().granularity());
760
761 m_frame->selection().setNonDirectionalSelectionIfNeeded(newSelection, m_frame->selection().granularity(),
762 FrameSelection::AdjustEndpointsAtBidiBoundary);
763 }
764
handleMouseReleaseEvent(const MouseEventWithHitTestResults & event)765 bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& event)
766 {
767 AutoscrollController* controller = autoscrollController();
768 if (controller && controller->autoscrollInProgress())
769 stopAutoscroll();
770
771 // Used to prevent mouseMoveEvent from initiating a drag before
772 // the mouse is pressed again.
773 m_mousePressed = false;
774 m_capturesDragging = false;
775 m_mouseDownMayStartDrag = false;
776 m_mouseDownMayStartSelect = false;
777 m_mouseDownMayStartAutoscroll = false;
778 m_mouseDownWasInSubframe = false;
779
780 bool handled = false;
781
782 // Clear the selection if the mouse didn't move after the last mouse
783 // press and it's not a context menu click. We do this so when clicking
784 // on the selection, the selection goes away. However, if we are
785 // editing, place the caret.
786 if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection
787 && m_dragStartPos == event.event().position()
788 && m_frame->selection().isRange()
789 && event.event().button() != RightButton) {
790 VisibleSelection newSelection;
791 Node* node = event.targetNode();
792 bool caretBrowsing = m_frame->settings() && m_frame->settings()->caretBrowsingEnabled();
793 if (node && node->renderer() && (caretBrowsing || node->rendererIsEditable())) {
794 VisiblePosition pos = VisiblePosition(node->renderer()->positionForPoint(event.localPoint()));
795 newSelection = VisibleSelection(pos);
796 }
797
798 setSelectionIfNeeded(m_frame->selection(), newSelection);
799
800 handled = true;
801 }
802
803 m_frame->selection().notifyRendererOfSelectionChange(UserTriggered);
804
805 m_frame->selection().selectFrameElementInParentIfFullySelected();
806
807 if (event.event().button() == MiddleButton && !event.isOverLink()) {
808 // Ignore handled, since we want to paste to where the caret was placed anyway.
809 handled = handlePasteGlobalSelection(event.event()) || handled;
810 }
811
812 return handled;
813 }
814
815 #if OS(WIN)
816
startPanScrolling(RenderObject * renderer)817 void EventHandler::startPanScrolling(RenderObject* renderer)
818 {
819 if (!renderer->isBox())
820 return;
821 AutoscrollController* controller = autoscrollController();
822 if (!controller)
823 return;
824 controller->startPanScrolling(toRenderBox(renderer), lastKnownMousePosition());
825 invalidateClick();
826 }
827
828 #endif // OS(WIN)
829
autoscrollController() const830 AutoscrollController* EventHandler::autoscrollController() const
831 {
832 if (Page* page = m_frame->page())
833 return &page->autoscrollController();
834 return 0;
835 }
836
panScrollInProgress() const837 bool EventHandler::panScrollInProgress() const
838 {
839 return autoscrollController() && autoscrollController()->panScrollInProgress();
840 }
841
hitTestResultAtPoint(const LayoutPoint & point,HitTestRequest::HitTestRequestType hitType,const LayoutSize & padding)842 HitTestResult EventHandler::hitTestResultAtPoint(const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType, const LayoutSize& padding)
843 {
844 TRACE_EVENT0("webkit", "EventHandler::hitTestResultAtPoint");
845
846 // We always send hitTestResultAtPoint to the main frame if we have one,
847 // otherwise we might hit areas that are obscured by higher frames.
848 if (Page* page = m_frame->page()) {
849 LocalFrame* mainFrame = page->mainFrame()->isLocalFrame() ? page->deprecatedLocalMainFrame() : 0;
850 if (mainFrame && m_frame != mainFrame) {
851 FrameView* frameView = m_frame->view();
852 FrameView* mainView = mainFrame->view();
853 if (frameView && mainView) {
854 IntPoint mainFramePoint = mainView->rootViewToContents(frameView->contentsToRootView(roundedIntPoint(point)));
855 return mainFrame->eventHandler().hitTestResultAtPoint(mainFramePoint, hitType, padding);
856 }
857 }
858 }
859
860 HitTestResult result(point, padding.height(), padding.width(), padding.height(), padding.width());
861
862 // RenderView::hitTest causes a layout, and we don't want to hit that until the first
863 // layout because until then, there is nothing shown on the screen - the user can't
864 // have intentionally clicked on something belonging to this page. Furthermore,
865 // mousemove events before the first layout should not lead to a premature layout()
866 // happening, which could show a flash of white.
867 // See also the similar code in Document::prepareMouseEvent.
868 if (!m_frame->contentRenderer() || !m_frame->view() || !m_frame->view()->didFirstLayout())
869 return result;
870
871 // hitTestResultAtPoint is specifically used to hitTest into all frames, thus it always allows child frame content.
872 HitTestRequest request(hitType | HitTestRequest::AllowChildFrameContent);
873 m_frame->contentRenderer()->hitTest(request, result);
874 if (!request.readOnly())
875 m_frame->document()->updateHoverActiveState(request, result.innerElement());
876
877 if (request.disallowsShadowContent())
878 result.setToNodesInDocumentTreeScope();
879
880 return result;
881 }
882
stopAutoscroll()883 void EventHandler::stopAutoscroll()
884 {
885 if (AutoscrollController* controller = autoscrollController())
886 controller->stopAutoscroll();
887 }
888
mousePressNode() const889 Node* EventHandler::mousePressNode() const
890 {
891 return m_mousePressNode.get();
892 }
893
scroll(ScrollDirection direction,ScrollGranularity granularity,Node * startNode,Node ** stopNode,float delta,IntPoint absolutePoint)894 bool EventHandler::scroll(ScrollDirection direction, ScrollGranularity granularity, Node* startNode, Node** stopNode, float delta, IntPoint absolutePoint)
895 {
896 if (!delta)
897 return false;
898
899 Node* node = startNode;
900
901 if (!node)
902 node = m_frame->document()->focusedElement();
903
904 if (!node)
905 node = m_mousePressNode.get();
906
907 if (!node || !node->renderer())
908 return false;
909
910 RenderBox* curBox = node->renderer()->enclosingBox();
911 while (curBox && !curBox->isRenderView()) {
912 ScrollDirection physicalDirection = toPhysicalDirection(
913 direction, curBox->isHorizontalWritingMode(), curBox->style()->isFlippedBlocksWritingMode());
914
915 // If we're at the stopNode, we should try to scroll it but we shouldn't bubble past it
916 bool shouldStopBubbling = stopNode && *stopNode && curBox->node() == *stopNode;
917 bool didScroll = curBox->scroll(physicalDirection, granularity, delta);
918
919 if (didScroll && stopNode)
920 *stopNode = curBox->node();
921
922 if (didScroll || shouldStopBubbling) {
923 setFrameWasScrolledByUser();
924 return true;
925 }
926
927 curBox = curBox->containingBlock();
928 }
929
930 return false;
931 }
932
bubblingScroll(ScrollDirection direction,ScrollGranularity granularity,Node * startingNode)933 bool EventHandler::bubblingScroll(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
934 {
935 // The layout needs to be up to date to determine if we can scroll. We may be
936 // here because of an onLoad event, in which case the final layout hasn't been performed yet.
937 m_frame->document()->updateLayoutIgnorePendingStylesheets();
938 if (scroll(direction, granularity, startingNode))
939 return true;
940 LocalFrame* frame = m_frame;
941 FrameView* view = frame->view();
942 if (view && view->scroll(direction, granularity))
943 return true;
944 Frame* parentFrame = frame->tree().parent();
945 if (!parentFrame || !parentFrame->isLocalFrame())
946 return false;
947 // FIXME: Broken for OOPI.
948 return toLocalFrame(parentFrame)->eventHandler().bubblingScroll(direction, granularity, m_frame->deprecatedLocalOwner());
949 }
950
lastKnownMousePosition() const951 IntPoint EventHandler::lastKnownMousePosition() const
952 {
953 return m_lastKnownMousePosition;
954 }
955
subframeForTargetNode(Node * node)956 static LocalFrame* subframeForTargetNode(Node* node)
957 {
958 if (!node)
959 return 0;
960
961 RenderObject* renderer = node->renderer();
962 if (!renderer || !renderer->isWidget())
963 return 0;
964
965 // FIXME: This explicit check is needed only until RemoteFrames have RemoteFrameViews.
966 if (isHTMLFrameElementBase(node) && toHTMLFrameElementBase(node)->contentFrame() && toHTMLFrameElementBase(node)->contentFrame()->isRemoteFrameTemporary())
967 return 0;
968
969 Widget* widget = toRenderWidget(renderer)->widget();
970 if (!widget || !widget->isFrameView())
971 return 0;
972
973 return &toFrameView(widget)->frame();
974 }
975
subframeForHitTestResult(const MouseEventWithHitTestResults & hitTestResult)976 static LocalFrame* subframeForHitTestResult(const MouseEventWithHitTestResults& hitTestResult)
977 {
978 if (!hitTestResult.isOverWidget())
979 return 0;
980 return subframeForTargetNode(hitTestResult.targetNode());
981 }
982
isSubmitImage(Node * node)983 static bool isSubmitImage(Node* node)
984 {
985 return isHTMLInputElement(node) && toHTMLInputElement(node)->isImageButton();
986 }
987
useHandCursor(Node * node,bool isOverLink)988 bool EventHandler::useHandCursor(Node* node, bool isOverLink)
989 {
990 if (!node)
991 return false;
992
993 return ((isOverLink || isSubmitImage(node)) && !node->rendererIsEditable());
994 }
995
cursorUpdateTimerFired(Timer<EventHandler> *)996 void EventHandler::cursorUpdateTimerFired(Timer<EventHandler>*)
997 {
998 ASSERT(m_frame);
999 ASSERT(m_frame->document());
1000
1001 updateCursor();
1002 }
1003
updateCursor()1004 void EventHandler::updateCursor()
1005 {
1006 if (m_mousePositionIsUnknown)
1007 return;
1008
1009 FrameView* view = m_frame->view();
1010 if (!view || !view->shouldSetCursor())
1011 return;
1012
1013 RenderView* renderView = view->renderView();
1014 if (!renderView)
1015 return;
1016
1017 m_frame->document()->updateLayout();
1018
1019 HitTestRequest request(HitTestRequest::ReadOnly);
1020 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
1021 renderView->hitTest(request, result);
1022
1023 OptionalCursor optionalCursor = selectCursor(result);
1024 if (optionalCursor.isCursorChange()) {
1025 m_currentMouseCursor = optionalCursor.cursor();
1026 view->setCursor(m_currentMouseCursor);
1027 }
1028 }
1029
selectCursor(const HitTestResult & result)1030 OptionalCursor EventHandler::selectCursor(const HitTestResult& result)
1031 {
1032 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1033 return NoCursorChange;
1034
1035 Page* page = m_frame->page();
1036 if (!page)
1037 return NoCursorChange;
1038 #if OS(WIN)
1039 if (panScrollInProgress())
1040 return NoCursorChange;
1041 #endif
1042
1043 Node* node = result.innerPossiblyPseudoNode();
1044 if (!node)
1045 return selectAutoCursor(result, node, iBeamCursor());
1046
1047 RenderObject* renderer = node->renderer();
1048 RenderStyle* style = renderer ? renderer->style() : 0;
1049
1050 if (renderer) {
1051 Cursor overrideCursor;
1052 switch (renderer->getCursor(roundedIntPoint(result.localPoint()), overrideCursor)) {
1053 case SetCursorBasedOnStyle:
1054 break;
1055 case SetCursor:
1056 return overrideCursor;
1057 case DoNotSetCursor:
1058 return NoCursorChange;
1059 }
1060 }
1061
1062 if (style && style->cursors()) {
1063 const CursorList* cursors = style->cursors();
1064 for (unsigned i = 0; i < cursors->size(); ++i) {
1065 StyleImage* styleImage = (*cursors)[i].image();
1066 if (!styleImage)
1067 continue;
1068 ImageResource* cachedImage = styleImage->cachedImage();
1069 if (!cachedImage)
1070 continue;
1071 float scale = styleImage->imageScaleFactor();
1072 // Get hotspot and convert from logical pixels to physical pixels.
1073 IntPoint hotSpot = (*cursors)[i].hotSpot();
1074 hotSpot.scale(scale, scale);
1075 IntSize size = cachedImage->imageForRenderer(renderer)->size();
1076 if (cachedImage->errorOccurred())
1077 continue;
1078 // Limit the size of cursors (in UI pixels) so that they cannot be
1079 // used to cover UI elements in chrome.
1080 size.scale(1 / scale);
1081 if (size.width() > maximumCursorSize || size.height() > maximumCursorSize)
1082 continue;
1083
1084 Image* image = cachedImage->imageForRenderer(renderer);
1085 // Ensure no overflow possible in calculations above.
1086 if (scale < minimumCursorScale)
1087 continue;
1088 return Cursor(image, hotSpot, scale);
1089 }
1090 }
1091
1092 switch (style ? style->cursor() : CURSOR_AUTO) {
1093 case CURSOR_AUTO: {
1094 bool horizontalText = !style || style->isHorizontalWritingMode();
1095 const Cursor& iBeam = horizontalText ? iBeamCursor() : verticalTextCursor();
1096 return selectAutoCursor(result, node, iBeam);
1097 }
1098 case CURSOR_CROSS:
1099 return crossCursor();
1100 case CURSOR_POINTER:
1101 return handCursor();
1102 case CURSOR_MOVE:
1103 return moveCursor();
1104 case CURSOR_ALL_SCROLL:
1105 return moveCursor();
1106 case CURSOR_E_RESIZE:
1107 return eastResizeCursor();
1108 case CURSOR_W_RESIZE:
1109 return westResizeCursor();
1110 case CURSOR_N_RESIZE:
1111 return northResizeCursor();
1112 case CURSOR_S_RESIZE:
1113 return southResizeCursor();
1114 case CURSOR_NE_RESIZE:
1115 return northEastResizeCursor();
1116 case CURSOR_SW_RESIZE:
1117 return southWestResizeCursor();
1118 case CURSOR_NW_RESIZE:
1119 return northWestResizeCursor();
1120 case CURSOR_SE_RESIZE:
1121 return southEastResizeCursor();
1122 case CURSOR_NS_RESIZE:
1123 return northSouthResizeCursor();
1124 case CURSOR_EW_RESIZE:
1125 return eastWestResizeCursor();
1126 case CURSOR_NESW_RESIZE:
1127 return northEastSouthWestResizeCursor();
1128 case CURSOR_NWSE_RESIZE:
1129 return northWestSouthEastResizeCursor();
1130 case CURSOR_COL_RESIZE:
1131 return columnResizeCursor();
1132 case CURSOR_ROW_RESIZE:
1133 return rowResizeCursor();
1134 case CURSOR_TEXT:
1135 return iBeamCursor();
1136 case CURSOR_WAIT:
1137 return waitCursor();
1138 case CURSOR_HELP:
1139 return helpCursor();
1140 case CURSOR_VERTICAL_TEXT:
1141 return verticalTextCursor();
1142 case CURSOR_CELL:
1143 return cellCursor();
1144 case CURSOR_CONTEXT_MENU:
1145 return contextMenuCursor();
1146 case CURSOR_PROGRESS:
1147 return progressCursor();
1148 case CURSOR_NO_DROP:
1149 return noDropCursor();
1150 case CURSOR_ALIAS:
1151 return aliasCursor();
1152 case CURSOR_COPY:
1153 return copyCursor();
1154 case CURSOR_NONE:
1155 return noneCursor();
1156 case CURSOR_NOT_ALLOWED:
1157 return notAllowedCursor();
1158 case CURSOR_DEFAULT:
1159 return pointerCursor();
1160 case CURSOR_ZOOM_IN:
1161 return zoomInCursor();
1162 case CURSOR_ZOOM_OUT:
1163 return zoomOutCursor();
1164 case CURSOR_WEBKIT_GRAB:
1165 return grabCursor();
1166 case CURSOR_WEBKIT_GRABBING:
1167 return grabbingCursor();
1168 }
1169 return pointerCursor();
1170 }
1171
selectAutoCursor(const HitTestResult & result,Node * node,const Cursor & iBeam)1172 OptionalCursor EventHandler::selectAutoCursor(const HitTestResult& result, Node* node, const Cursor& iBeam)
1173 {
1174 bool editable = (node && node->rendererIsEditable());
1175
1176 if (useHandCursor(node, result.isOverLink()))
1177 return handCursor();
1178
1179 bool inResizer = false;
1180 RenderObject* renderer = node ? node->renderer() : 0;
1181 if (renderer && m_frame->view()) {
1182 RenderLayer* layer = renderer->enclosingLayer();
1183 inResizer = layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(result.roundedPointInMainFrame(), ResizerForPointer);
1184 }
1185
1186 // During selection, use an I-beam no matter what we're over.
1187 // If a drag may be starting or we're capturing mouse events for a particular node, don't treat this as a selection.
1188 if (m_mousePressed && m_mouseDownMayStartSelect
1189 && !m_mouseDownMayStartDrag
1190 && m_frame->selection().isCaretOrRange()
1191 && !m_capturingMouseEventsNode) {
1192 return iBeam;
1193 }
1194
1195 if ((editable || (renderer && renderer->isText() && node->canStartSelection())) && !inResizer && !result.scrollbar())
1196 return iBeam;
1197 return pointerCursor();
1198 }
1199
documentPointForWindowPoint(LocalFrame * frame,const IntPoint & windowPoint)1200 static LayoutPoint documentPointForWindowPoint(LocalFrame* frame, const IntPoint& windowPoint)
1201 {
1202 FrameView* view = frame->view();
1203 // FIXME: Is it really OK to use the wrong coordinates here when view is 0?
1204 // Historically the code would just crash; this is clearly no worse than that.
1205 return view ? view->windowToContents(windowPoint) : windowPoint;
1206 }
1207
handleMousePressEvent(const PlatformMouseEvent & mouseEvent)1208 bool EventHandler::handleMousePressEvent(const PlatformMouseEvent& mouseEvent)
1209 {
1210 TRACE_EVENT0("webkit", "EventHandler::handleMousePressEvent");
1211
1212 RefPtr<FrameView> protector(m_frame->view());
1213
1214 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
1215 m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken = gestureIndicator.currentToken();
1216
1217 cancelFakeMouseMoveEvent();
1218 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1219 m_capturingMouseEventsNode = nullptr;
1220 m_mousePressed = true;
1221 m_capturesDragging = true;
1222 setLastKnownMousePosition(mouseEvent);
1223 m_mouseDownTimestamp = mouseEvent.timestamp();
1224 m_mouseDownMayStartDrag = false;
1225 m_mouseDownMayStartSelect = false;
1226 m_mouseDownMayStartAutoscroll = false;
1227 if (FrameView* view = m_frame->view())
1228 m_mouseDownPos = view->windowToContents(mouseEvent.position());
1229 else {
1230 invalidateClick();
1231 return false;
1232 }
1233 m_mouseDownWasInSubframe = false;
1234
1235 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1236 if (mouseEvent.fromTouch())
1237 hitType |= HitTestRequest::ReadOnly;
1238 HitTestRequest request(hitType);
1239 // Save the document point we generate in case the window coordinate is invalidated by what happens
1240 // when we dispatch the event.
1241 LayoutPoint documentPoint = documentPointForWindowPoint(m_frame, mouseEvent.position());
1242 MouseEventWithHitTestResults mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1243
1244 if (!mev.targetNode()) {
1245 invalidateClick();
1246 return false;
1247 }
1248
1249 m_mousePressNode = mev.targetNode();
1250
1251 RefPtr<LocalFrame> subframe = subframeForHitTestResult(mev);
1252 if (subframe && passMousePressEventToSubframe(mev, subframe.get())) {
1253 // Start capturing future events for this frame. We only do this if we didn't clear
1254 // the m_mousePressed flag, which may happen if an AppKit widget entered a modal event loop.
1255 m_capturesDragging = subframe->eventHandler().capturesDragging();
1256 if (m_mousePressed && m_capturesDragging) {
1257 m_capturingMouseEventsNode = mev.targetNode();
1258 m_eventHandlerWillResetCapturingMouseEventsNode = true;
1259 }
1260 invalidateClick();
1261 return true;
1262 }
1263
1264 #if OS(WIN)
1265 // We store whether pan scrolling is in progress before calling stopAutoscroll()
1266 // because it will set m_autoscrollType to NoAutoscroll on return.
1267 bool isPanScrollInProgress = panScrollInProgress();
1268 stopAutoscroll();
1269 if (isPanScrollInProgress) {
1270 // We invalidate the click when exiting pan scrolling so that we don't inadvertently navigate
1271 // away from the current page (e.g. the click was on a hyperlink). See <rdar://problem/6095023>.
1272 invalidateClick();
1273 return true;
1274 }
1275 #endif
1276
1277 m_clickCount = mouseEvent.clickCount();
1278 m_clickNode = mev.targetNode()->isTextNode() ? NodeRenderingTraversal::parent(mev.targetNode()) : mev.targetNode();
1279
1280 if (FrameView* view = m_frame->view()) {
1281 RenderLayer* layer = mev.targetNode()->renderer() ? mev.targetNode()->renderer()->enclosingLayer() : 0;
1282 IntPoint p = view->windowToContents(mouseEvent.position());
1283 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForPointer)) {
1284 m_resizeScrollableArea = layer->scrollableArea();
1285 m_resizeScrollableArea->setInResizeMode(true);
1286 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
1287 invalidateClick();
1288 return true;
1289 }
1290 }
1291
1292 m_frame->selection().setCaretBlinkingSuspended(true);
1293
1294 bool swallowEvent = !dispatchMouseEvent(EventTypeNames::mousedown, mev.targetNode(), m_clickCount, mouseEvent, true);
1295 swallowEvent = swallowEvent || !handleMouseFocus(mouseEvent);
1296 m_capturesDragging = !swallowEvent || mev.scrollbar();
1297
1298 // If the hit testing originally determined the event was in a scrollbar, refetch the MouseEventWithHitTestResults
1299 // in case the scrollbar widget was destroyed when the mouse event was handled.
1300 if (mev.scrollbar()) {
1301 const bool wasLastScrollBar = mev.scrollbar() == m_lastScrollbarUnderMouse.get();
1302 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1303 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1304 if (wasLastScrollBar && mev.scrollbar() != m_lastScrollbarUnderMouse.get())
1305 m_lastScrollbarUnderMouse = nullptr;
1306 }
1307
1308 if (swallowEvent) {
1309 // scrollbars should get events anyway, even disabled controls might be scrollable
1310 passMousePressEventToScrollbar(mev);
1311 } else {
1312 if (shouldRefetchEventTarget(mev)) {
1313 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1314 mev = m_frame->document()->prepareMouseEvent(request, documentPoint, mouseEvent);
1315 }
1316
1317 if (passMousePressEventToScrollbar(mev))
1318 swallowEvent = true;
1319 else
1320 swallowEvent = handleMousePressEvent(mev);
1321 }
1322
1323 return swallowEvent;
1324 }
1325
layerForNode(Node * node)1326 static RenderLayer* layerForNode(Node* node)
1327 {
1328 if (!node)
1329 return 0;
1330
1331 RenderObject* renderer = node->renderer();
1332 if (!renderer)
1333 return 0;
1334
1335 RenderLayer* layer = renderer->enclosingLayer();
1336 if (!layer)
1337 return 0;
1338
1339 return layer;
1340 }
1341
associatedScrollableArea(const RenderLayer * layer) const1342 ScrollableArea* EventHandler::associatedScrollableArea(const RenderLayer* layer) const
1343 {
1344 if (RenderLayerScrollableArea* scrollableArea = layer->scrollableArea()) {
1345 if (scrollableArea->scrollsOverflow())
1346 return scrollableArea;
1347 }
1348
1349 return 0;
1350 }
1351
handleMouseMoveEvent(const PlatformMouseEvent & event)1352 bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& event)
1353 {
1354 TRACE_EVENT0("webkit", "EventHandler::handleMouseMoveEvent");
1355
1356 RefPtr<FrameView> protector(m_frame->view());
1357 MaximumDurationTracker maxDurationTracker(&m_maxMouseMovedDuration);
1358
1359 HitTestResult hoveredNode = HitTestResult(LayoutPoint());
1360 bool result = handleMouseMoveOrLeaveEvent(event, &hoveredNode);
1361
1362 Page* page = m_frame->page();
1363 if (!page)
1364 return result;
1365
1366 if (RenderLayer* layer = layerForNode(hoveredNode.innerNode())) {
1367 if (ScrollableArea* layerScrollableArea = associatedScrollableArea(layer))
1368 layerScrollableArea->mouseMovedInContentArea();
1369 }
1370
1371 if (FrameView* frameView = m_frame->view())
1372 frameView->mouseMovedInContentArea();
1373
1374 hoveredNode.setToShadowHostIfInUserAgentShadowRoot();
1375 page->chrome().mouseDidMoveOverElement(hoveredNode, event.modifierFlags());
1376 page->chrome().setToolTip(hoveredNode);
1377
1378 return result;
1379 }
1380
handleMouseLeaveEvent(const PlatformMouseEvent & event)1381 void EventHandler::handleMouseLeaveEvent(const PlatformMouseEvent& event)
1382 {
1383 TRACE_EVENT0("webkit", "EventHandler::handleMouseLeaveEvent");
1384
1385 RefPtr<FrameView> protector(m_frame->view());
1386 handleMouseMoveOrLeaveEvent(event);
1387 }
1388
handleMouseMoveOrLeaveEvent(const PlatformMouseEvent & mouseEvent,HitTestResult * hoveredNode,bool onlyUpdateScrollbars)1389 bool EventHandler::handleMouseMoveOrLeaveEvent(const PlatformMouseEvent& mouseEvent, HitTestResult* hoveredNode, bool onlyUpdateScrollbars)
1390 {
1391 ASSERT(m_frame);
1392 ASSERT(m_frame->view());
1393
1394 setLastKnownMousePosition(mouseEvent);
1395
1396 if (m_hoverTimer.isActive())
1397 m_hoverTimer.stop();
1398
1399 m_cursorUpdateTimer.stop();
1400
1401 cancelFakeMouseMoveEvent();
1402
1403 if (m_svgPan) {
1404 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1405 return true;
1406 }
1407
1408 if (m_frameSetBeingResized)
1409 return !dispatchMouseEvent(EventTypeNames::mousemove, m_frameSetBeingResized.get(), 0, mouseEvent, false);
1410
1411 // Send events right to a scrollbar if the mouse is pressed.
1412 if (m_lastScrollbarUnderMouse && m_mousePressed) {
1413 m_lastScrollbarUnderMouse->mouseMoved(mouseEvent);
1414 return true;
1415 }
1416
1417 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1418 if (mouseEvent.fromTouch())
1419 hitType |= HitTestRequest::ReadOnly;
1420
1421 if (m_mousePressed)
1422 hitType |= HitTestRequest::Active;
1423 else if (onlyUpdateScrollbars) {
1424 // Mouse events should be treated as "read-only" if we're updating only scrollbars. This
1425 // means that :hover and :active freeze in the state they were in, rather than updating
1426 // for nodes the mouse moves while the window is not key (which will be the case if
1427 // onlyUpdateScrollbars is true).
1428 hitType |= HitTestRequest::ReadOnly;
1429 }
1430
1431 // Treat any mouse move events as readonly if the user is currently touching the screen.
1432 if (m_touchPressed)
1433 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
1434 HitTestRequest request(hitType);
1435 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1436 if (hoveredNode)
1437 *hoveredNode = mev.hitTestResult();
1438
1439 Scrollbar* scrollbar = 0;
1440
1441 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode())
1442 m_resizeScrollableArea->resize(mouseEvent, m_offsetFromResizeCorner);
1443 else {
1444 if (FrameView* view = m_frame->view())
1445 scrollbar = view->scrollbarAtPoint(mouseEvent.position());
1446
1447 if (!scrollbar)
1448 scrollbar = mev.scrollbar();
1449
1450 updateLastScrollbarUnderMouse(scrollbar, !m_mousePressed);
1451 if (onlyUpdateScrollbars)
1452 return true;
1453 }
1454
1455 bool swallowEvent = false;
1456 RefPtr<LocalFrame> newSubframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1457
1458 // 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.
1459 if (m_lastMouseMoveEventSubframe && m_lastMouseMoveEventSubframe->tree().isDescendantOf(m_frame) && m_lastMouseMoveEventSubframe != newSubframe)
1460 passMouseMoveEventToSubframe(mev, m_lastMouseMoveEventSubframe.get());
1461
1462 if (newSubframe) {
1463 // Update over/out state before passing the event to the subframe.
1464 updateMouseEventTargetNode(mev.targetNode(), mouseEvent, true);
1465
1466 // Event dispatch in updateMouseEventTargetNode may have caused the subframe of the target
1467 // node to be detached from its FrameView, in which case the event should not be passed.
1468 if (newSubframe->view())
1469 swallowEvent |= passMouseMoveEventToSubframe(mev, newSubframe.get(), hoveredNode);
1470 } else {
1471 if (scrollbar && !m_mousePressed)
1472 scrollbar->mouseMoved(mouseEvent); // Handle hover effects on platforms that support visual feedback on scrollbar hovering.
1473 if (FrameView* view = m_frame->view()) {
1474 OptionalCursor optionalCursor = selectCursor(mev.hitTestResult());
1475 if (optionalCursor.isCursorChange()) {
1476 m_currentMouseCursor = optionalCursor.cursor();
1477 view->setCursor(m_currentMouseCursor);
1478 }
1479 }
1480 }
1481
1482 m_lastMouseMoveEventSubframe = newSubframe;
1483
1484 if (swallowEvent)
1485 return true;
1486
1487 swallowEvent = !dispatchMouseEvent(EventTypeNames::mousemove, mev.targetNode(), 0, mouseEvent, true);
1488 if (!swallowEvent)
1489 swallowEvent = handleMouseDraggedEvent(mev);
1490
1491 return swallowEvent;
1492 }
1493
invalidateClick()1494 void EventHandler::invalidateClick()
1495 {
1496 m_clickCount = 0;
1497 m_clickNode = nullptr;
1498 }
1499
parentForClickEvent(const Node & node)1500 static Node* parentForClickEvent(const Node& node)
1501 {
1502 // IE doesn't dispatch click events for mousedown/mouseup events across form
1503 // controls.
1504 if (node.isHTMLElement() && toHTMLElement(node).isInteractiveContent())
1505 return 0;
1506 return NodeRenderingTraversal::parent(&node);
1507 }
1508
handleMouseReleaseEvent(const PlatformMouseEvent & mouseEvent)1509 bool EventHandler::handleMouseReleaseEvent(const PlatformMouseEvent& mouseEvent)
1510 {
1511 TRACE_EVENT0("webkit", "EventHandler::handleMouseReleaseEvent");
1512
1513 RefPtr<FrameView> protector(m_frame->view());
1514
1515 m_frame->selection().setCaretBlinkingSuspended(false);
1516
1517 OwnPtr<UserGestureIndicator> gestureIndicator;
1518
1519 if (m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken)
1520 gestureIndicator = adoptPtr(new UserGestureIndicator(m_frame->localFrameRoot()->eventHandler().m_lastMouseDownUserGestureToken.release()));
1521 else
1522 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
1523
1524 #if OS(WIN)
1525 if (Page* page = m_frame->page())
1526 page->autoscrollController().handleMouseReleaseForPanScrolling(m_frame, mouseEvent);
1527 #endif
1528
1529 m_mousePressed = false;
1530 setLastKnownMousePosition(mouseEvent);
1531
1532 if (m_svgPan) {
1533 m_svgPan = false;
1534 m_frame->document()->accessSVGExtensions().updatePan(m_frame->view()->windowToContents(m_lastKnownMousePosition));
1535 return true;
1536 }
1537
1538 if (m_frameSetBeingResized)
1539 return !dispatchMouseEvent(EventTypeNames::mouseup, m_frameSetBeingResized.get(), m_clickCount, mouseEvent, false);
1540
1541 if (m_lastScrollbarUnderMouse) {
1542 invalidateClick();
1543 m_lastScrollbarUnderMouse->mouseUp(mouseEvent);
1544 bool setUnder = false;
1545 return !dispatchMouseEvent(EventTypeNames::mouseup, m_lastNodeUnderMouse.get(), m_clickCount, mouseEvent, setUnder);
1546 }
1547
1548 HitTestRequest::HitTestRequestType hitType = HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent;
1549 if (mouseEvent.fromTouch())
1550 hitType |= HitTestRequest::ReadOnly;
1551 HitTestRequest request(hitType);
1552 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseEvent);
1553 LocalFrame* subframe = m_capturingMouseEventsNode.get() ? subframeForTargetNode(m_capturingMouseEventsNode.get()) : subframeForHitTestResult(mev);
1554 if (m_eventHandlerWillResetCapturingMouseEventsNode)
1555 m_capturingMouseEventsNode = nullptr;
1556 if (subframe && passMouseReleaseEventToSubframe(mev, subframe))
1557 return true;
1558
1559 bool swallowMouseUpEvent = !dispatchMouseEvent(EventTypeNames::mouseup, mev.targetNode(), m_clickCount, mouseEvent, false);
1560
1561 bool contextMenuEvent = mouseEvent.button() == RightButton;
1562 #if OS(MACOSX)
1563 // FIXME: The Mac port achieves the same behavior by checking whether the context menu is currently open in WebPage::mouseEvent(). Consider merging the implementations.
1564 if (mouseEvent.button() == LeftButton && mouseEvent.modifiers() & PlatformEvent::CtrlKey)
1565 contextMenuEvent = true;
1566 #endif
1567
1568 bool swallowClickEvent = false;
1569 if (m_clickCount > 0 && !contextMenuEvent && mev.targetNode() && m_clickNode) {
1570 if (Node* clickTargetNode = mev.targetNode()->commonAncestor(*m_clickNode, parentForClickEvent))
1571 swallowClickEvent = !dispatchMouseEvent(EventTypeNames::click, clickTargetNode, m_clickCount, mouseEvent, true);
1572 }
1573
1574 if (m_resizeScrollableArea) {
1575 m_resizeScrollableArea->setInResizeMode(false);
1576 m_resizeScrollableArea = 0;
1577 }
1578
1579 bool swallowMouseReleaseEvent = false;
1580 if (!swallowMouseUpEvent)
1581 swallowMouseReleaseEvent = handleMouseReleaseEvent(mev);
1582
1583 invalidateClick();
1584
1585 return swallowMouseUpEvent || swallowClickEvent || swallowMouseReleaseEvent;
1586 }
1587
handlePasteGlobalSelection(const PlatformMouseEvent & mouseEvent)1588 bool EventHandler::handlePasteGlobalSelection(const PlatformMouseEvent& mouseEvent)
1589 {
1590 // If the event was a middle click, attempt to copy global selection in after
1591 // the newly set caret position.
1592 //
1593 // This code is called from either the mouse up or mouse down handling. There
1594 // is some debate about when the global selection is pasted:
1595 // xterm: pastes on up.
1596 // GTK: pastes on down.
1597 // Qt: pastes on up.
1598 // Firefox: pastes on up.
1599 // Chromium: pastes on up.
1600 //
1601 // There is something of a webcompat angle to this well, as highlighted by
1602 // crbug.com/14608. Pages can clear text boxes 'onclick' and, if we paste on
1603 // down then the text is pasted just before the onclick handler runs and
1604 // clears the text box. So it's important this happens after the event
1605 // handlers have been fired.
1606 if (mouseEvent.type() != PlatformEvent::MouseReleased)
1607 return false;
1608
1609 if (!m_frame->page())
1610 return false;
1611 Frame* focusFrame = m_frame->page()->focusController().focusedOrMainFrame();
1612 // Do not paste here if the focus was moved somewhere else.
1613 if (m_frame == focusFrame && m_frame->editor().behavior().supportsGlobalSelection())
1614 return m_frame->editor().command("PasteGlobalSelection").execute();
1615
1616 return false;
1617 }
1618
1619
dispatchDragEvent(const AtomicString & eventType,Node * dragTarget,const PlatformMouseEvent & event,Clipboard * clipboard)1620 bool EventHandler::dispatchDragEvent(const AtomicString& eventType, Node* dragTarget, const PlatformMouseEvent& event, Clipboard* clipboard)
1621 {
1622 FrameView* view = m_frame->view();
1623
1624 // FIXME: We might want to dispatch a dragleave even if the view is gone.
1625 if (!view)
1626 return false;
1627
1628 RefPtrWillBeRawPtr<MouseEvent> me = MouseEvent::create(eventType,
1629 true, true, m_frame->document()->domWindow(),
1630 0, event.globalPosition().x(), event.globalPosition().y(), event.position().x(), event.position().y(),
1631 event.movementDelta().x(), event.movementDelta().y(),
1632 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
1633 0, nullptr, clipboard);
1634
1635 dragTarget->dispatchEvent(me.get(), IGNORE_EXCEPTION);
1636 return me->defaultPrevented();
1637 }
1638
targetIsFrame(Node * target,LocalFrame * & frame)1639 static bool targetIsFrame(Node* target, LocalFrame*& frame)
1640 {
1641 if (!isHTMLFrameElementBase(target))
1642 return false;
1643
1644 // Cross-process drag and drop is not yet supported.
1645 if (toHTMLFrameElementBase(target)->contentFrame() && !toHTMLFrameElementBase(target)->contentFrame()->isLocalFrame())
1646 return false;
1647
1648 frame = toLocalFrame(toHTMLFrameElementBase(target)->contentFrame());
1649 return true;
1650 }
1651
findDropZone(Node * target,Clipboard * clipboard)1652 static bool findDropZone(Node* target, Clipboard* clipboard)
1653 {
1654 Element* element = target->isElementNode() ? toElement(target) : target->parentElement();
1655 for (; element; element = element->parentElement()) {
1656 bool matched = false;
1657 AtomicString dropZoneStr = element->fastGetAttribute(webkitdropzoneAttr);
1658
1659 if (dropZoneStr.isEmpty())
1660 continue;
1661
1662 dropZoneStr = dropZoneStr.lower();
1663
1664 SpaceSplitString keywords(dropZoneStr, false);
1665 if (keywords.isNull())
1666 continue;
1667
1668 DragOperation dragOperation = DragOperationNone;
1669 for (unsigned i = 0; i < keywords.size(); i++) {
1670 DragOperation op = convertDropZoneOperationToDragOperation(keywords[i]);
1671 if (op != DragOperationNone) {
1672 if (dragOperation == DragOperationNone)
1673 dragOperation = op;
1674 } else
1675 matched = matched || clipboard->hasDropZoneType(keywords[i].string());
1676
1677 if (matched && dragOperation != DragOperationNone)
1678 break;
1679 }
1680 if (matched) {
1681 clipboard->setDropEffect(convertDragOperationToDropZoneOperation(dragOperation));
1682 return true;
1683 }
1684 }
1685 return false;
1686 }
1687
updateDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1688 bool EventHandler::updateDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1689 {
1690 bool accept = false;
1691
1692 if (!m_frame->view())
1693 return false;
1694
1695 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1696 MouseEventWithHitTestResults mev = prepareMouseEvent(request, event);
1697
1698 // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1699 RefPtrWillBeRawPtr<Node> newTarget = mev.targetNode();
1700 if (newTarget && newTarget->isTextNode())
1701 newTarget = NodeRenderingTraversal::parent(newTarget.get());
1702
1703 if (AutoscrollController* controller = autoscrollController())
1704 controller->updateDragAndDrop(newTarget.get(), event.position(), event.timestamp());
1705
1706 if (m_dragTarget != newTarget) {
1707 // FIXME: this ordering was explicitly chosen to match WinIE. However,
1708 // it is sometimes incorrect when dragging within subframes, as seen with
1709 // LayoutTests/fast/events/drag-in-frames.html.
1710 //
1711 // 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>.
1712 LocalFrame* targetFrame;
1713 if (targetIsFrame(newTarget.get(), targetFrame)) {
1714 if (targetFrame)
1715 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1716 } else if (newTarget) {
1717 // 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.
1718 if (dragState().m_dragSrc) {
1719 // for now we don't care if event handler cancels default behavior, since there is none
1720 dispatchDragSrcEvent(EventTypeNames::drag, event);
1721 }
1722 accept = dispatchDragEvent(EventTypeNames::dragenter, newTarget.get(), event, clipboard);
1723 if (!accept)
1724 accept = findDropZone(newTarget.get(), clipboard);
1725 }
1726
1727 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1728 if (targetFrame)
1729 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1730 } else if (m_dragTarget)
1731 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1732
1733 if (newTarget) {
1734 // We do not explicitly call dispatchDragEvent here because it could ultimately result in the appearance that
1735 // two dragover events fired. So, we mark that we should only fire a dragover event on the next call to this function.
1736 m_shouldOnlyFireDragOverEvent = true;
1737 }
1738 } else {
1739 LocalFrame* targetFrame;
1740 if (targetIsFrame(newTarget.get(), targetFrame)) {
1741 if (targetFrame)
1742 accept = targetFrame->eventHandler().updateDragAndDrop(event, clipboard);
1743 } else if (newTarget) {
1744 // Note, when dealing with sub-frames, we may need to fire only a dragover event as a drag event may have been fired earlier.
1745 if (!m_shouldOnlyFireDragOverEvent && dragState().m_dragSrc) {
1746 // for now we don't care if event handler cancels default behavior, since there is none
1747 dispatchDragSrcEvent(EventTypeNames::drag, event);
1748 }
1749 accept = dispatchDragEvent(EventTypeNames::dragover, newTarget.get(), event, clipboard);
1750 if (!accept)
1751 accept = findDropZone(newTarget.get(), clipboard);
1752 m_shouldOnlyFireDragOverEvent = false;
1753 }
1754 }
1755 m_dragTarget = newTarget;
1756
1757 return accept;
1758 }
1759
cancelDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1760 void EventHandler::cancelDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1761 {
1762 LocalFrame* targetFrame;
1763 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1764 if (targetFrame)
1765 targetFrame->eventHandler().cancelDragAndDrop(event, clipboard);
1766 } else if (m_dragTarget.get()) {
1767 if (dragState().m_dragSrc)
1768 dispatchDragSrcEvent(EventTypeNames::drag, event);
1769 dispatchDragEvent(EventTypeNames::dragleave, m_dragTarget.get(), event, clipboard);
1770 }
1771 clearDragState();
1772 }
1773
performDragAndDrop(const PlatformMouseEvent & event,Clipboard * clipboard)1774 bool EventHandler::performDragAndDrop(const PlatformMouseEvent& event, Clipboard* clipboard)
1775 {
1776 LocalFrame* targetFrame;
1777 bool preventedDefault = false;
1778 if (targetIsFrame(m_dragTarget.get(), targetFrame)) {
1779 if (targetFrame)
1780 preventedDefault = targetFrame->eventHandler().performDragAndDrop(event, clipboard);
1781 } else if (m_dragTarget.get())
1782 preventedDefault = dispatchDragEvent(EventTypeNames::drop, m_dragTarget.get(), event, clipboard);
1783 clearDragState();
1784 return preventedDefault;
1785 }
1786
clearDragState()1787 void EventHandler::clearDragState()
1788 {
1789 stopAutoscroll();
1790 m_dragTarget = nullptr;
1791 m_capturingMouseEventsNode = nullptr;
1792 m_shouldOnlyFireDragOverEvent = false;
1793 }
1794
setCapturingMouseEventsNode(PassRefPtrWillBeRawPtr<Node> n)1795 void EventHandler::setCapturingMouseEventsNode(PassRefPtrWillBeRawPtr<Node> n)
1796 {
1797 m_capturingMouseEventsNode = n;
1798 m_eventHandlerWillResetCapturingMouseEventsNode = false;
1799 }
1800
prepareMouseEvent(const HitTestRequest & request,const PlatformMouseEvent & mev)1801 MouseEventWithHitTestResults EventHandler::prepareMouseEvent(const HitTestRequest& request, const PlatformMouseEvent& mev)
1802 {
1803 ASSERT(m_frame);
1804 ASSERT(m_frame->document());
1805
1806 return m_frame->document()->prepareMouseEvent(request, documentPointForWindowPoint(m_frame, mev.position()), mev);
1807 }
1808
updateMouseEventTargetNode(Node * targetNode,const PlatformMouseEvent & mouseEvent,bool fireMouseOverOut)1809 void EventHandler::updateMouseEventTargetNode(Node* targetNode, const PlatformMouseEvent& mouseEvent, bool fireMouseOverOut)
1810 {
1811 Node* result = targetNode;
1812
1813 // If we're capturing, we always go right to that node.
1814 if (m_capturingMouseEventsNode)
1815 result = m_capturingMouseEventsNode.get();
1816 else {
1817 // If the target node is a text node, dispatch on the parent node - rdar://4196646
1818 if (result && result->isTextNode())
1819 result = NodeRenderingTraversal::parent(result);
1820 }
1821 m_nodeUnderMouse = result;
1822
1823 // Fire mouseout/mouseover if the mouse has shifted to a different node.
1824 if (fireMouseOverOut) {
1825 RenderLayer* layerForLastNode = layerForNode(m_lastNodeUnderMouse.get());
1826 RenderLayer* layerForNodeUnderMouse = layerForNode(m_nodeUnderMouse.get());
1827 Page* page = m_frame->page();
1828
1829 if (m_lastNodeUnderMouse && (!m_nodeUnderMouse || m_nodeUnderMouse->document() != m_frame->document())) {
1830 // The mouse has moved between frames.
1831 if (LocalFrame* frame = m_lastNodeUnderMouse->document().frame()) {
1832 if (FrameView* frameView = frame->view())
1833 frameView->mouseExitedContentArea();
1834 }
1835 } else if (page && (layerForLastNode && (!layerForNodeUnderMouse || layerForNodeUnderMouse != layerForLastNode))) {
1836 // The mouse has moved between layers.
1837 if (ScrollableArea* scrollableAreaForLastNode = associatedScrollableArea(layerForLastNode))
1838 scrollableAreaForLastNode->mouseExitedContentArea();
1839 }
1840
1841 if (m_nodeUnderMouse && (!m_lastNodeUnderMouse || m_lastNodeUnderMouse->document() != m_frame->document())) {
1842 // The mouse has moved between frames.
1843 if (LocalFrame* frame = m_nodeUnderMouse->document().frame()) {
1844 if (FrameView* frameView = frame->view())
1845 frameView->mouseEnteredContentArea();
1846 }
1847 } else if (page && (layerForNodeUnderMouse && (!layerForLastNode || layerForNodeUnderMouse != layerForLastNode))) {
1848 // The mouse has moved between layers.
1849 if (ScrollableArea* scrollableAreaForNodeUnderMouse = associatedScrollableArea(layerForNodeUnderMouse))
1850 scrollableAreaForNodeUnderMouse->mouseEnteredContentArea();
1851 }
1852
1853 if (m_lastNodeUnderMouse && m_lastNodeUnderMouse->document() != m_frame->document()) {
1854 m_lastNodeUnderMouse = nullptr;
1855 m_lastScrollbarUnderMouse = nullptr;
1856 }
1857
1858 if (m_lastNodeUnderMouse != m_nodeUnderMouse) {
1859 // send mouseout event to the old node
1860 if (m_lastNodeUnderMouse)
1861 m_lastNodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseout, 0, m_nodeUnderMouse.get());
1862 // send mouseover event to the new node
1863 if (m_nodeUnderMouse)
1864 m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, EventTypeNames::mouseover, 0, m_lastNodeUnderMouse.get());
1865 }
1866 m_lastNodeUnderMouse = m_nodeUnderMouse;
1867 }
1868 }
1869
1870 // The return value means 'continue default handling.'
dispatchMouseEvent(const AtomicString & eventType,Node * targetNode,int clickCount,const PlatformMouseEvent & mouseEvent,bool setUnder)1871 bool EventHandler::dispatchMouseEvent(const AtomicString& eventType, Node* targetNode, int clickCount, const PlatformMouseEvent& mouseEvent, bool setUnder)
1872 {
1873 updateMouseEventTargetNode(targetNode, mouseEvent, setUnder);
1874 return !m_nodeUnderMouse || m_nodeUnderMouse->dispatchMouseEvent(mouseEvent, eventType, clickCount);
1875 }
1876
1877 // The return value means 'continue default handling.'
handleMouseFocus(const PlatformMouseEvent & mouseEvent)1878 bool EventHandler::handleMouseFocus(const PlatformMouseEvent& mouseEvent)
1879 {
1880 // If clicking on a frame scrollbar, do not mess up with content focus.
1881 if (FrameView* view = m_frame->view()) {
1882 if (view->scrollbarAtPoint(mouseEvent.position()))
1883 return true;
1884 }
1885
1886 // The layout needs to be up to date to determine if an element is focusable.
1887 m_frame->document()->updateLayoutIgnorePendingStylesheets();
1888
1889 Element* element = 0;
1890 if (m_nodeUnderMouse)
1891 element = m_nodeUnderMouse->isElementNode() ? toElement(m_nodeUnderMouse) : m_nodeUnderMouse->parentOrShadowHostElement();
1892 for (; element; element = element->parentOrShadowHostElement()) {
1893 if (element->isFocusable() && element->focused())
1894 return true;
1895 if (element->isMouseFocusable())
1896 break;
1897 }
1898 ASSERT(!element || element->isMouseFocusable());
1899
1900 // To fix <rdar://problem/4895428> Can't drag selected ToDo, we don't focus
1901 // a node on mouse down if it's selected and inside a focused node. It will
1902 // be focused if the user does a mouseup over it, however, because the
1903 // mouseup will set a selection inside it, which will call
1904 // FrameSelection::setFocusedNodeIfNeeded.
1905 if (element
1906 && m_frame->selection().isRange()
1907 && m_frame->selection().toNormalizedRange()->compareNode(element, IGNORE_EXCEPTION) == Range::NODE_INSIDE
1908 && element->isDescendantOf(m_frame->document()->focusedElement()))
1909 return true;
1910
1911 // Only change the focus when clicking scrollbars if it can transfered to a
1912 // mouse focusable node.
1913 if (!element && isInsideScrollbar(mouseEvent.position()))
1914 return false;
1915
1916 if (Page* page = m_frame->page()) {
1917 // If focus shift is blocked, we eat the event. Note we should never
1918 // clear swallowEvent if the page already set it (e.g., by canceling
1919 // default behavior).
1920 if (element) {
1921 if (!page->focusController().setFocusedElement(element, m_frame, FocusTypeMouse))
1922 return false;
1923 } else {
1924 // We call setFocusedElement even with !element in order to blur
1925 // current focus element when a link is clicked; this is expected by
1926 // some sites that rely on onChange handlers running from form
1927 // fields before the button click is processed.
1928 if (!page->focusController().setFocusedElement(0, m_frame))
1929 return false;
1930 }
1931 }
1932
1933 return true;
1934 }
1935
isInsideScrollbar(const IntPoint & windowPoint) const1936 bool EventHandler::isInsideScrollbar(const IntPoint& windowPoint) const
1937 {
1938 if (RenderView* renderView = m_frame->contentRenderer()) {
1939 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1940 HitTestResult result(windowPoint);
1941 renderView->hitTest(request, result);
1942 return result.scrollbar();
1943 }
1944
1945 return false;
1946 }
1947
handleWheelEvent(const PlatformWheelEvent & event)1948 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
1949 {
1950 #define RETURN_WHEEL_EVENT_HANDLED() \
1951 { \
1952 setFrameWasScrolledByUser(); \
1953 return true; \
1954 }
1955
1956 Document* doc = m_frame->document();
1957
1958 if (!doc->renderView())
1959 return false;
1960
1961 RefPtr<FrameView> protector(m_frame->view());
1962
1963 FrameView* view = m_frame->view();
1964 if (!view)
1965 return false;
1966
1967 LayoutPoint vPoint = view->windowToContents(event.position());
1968
1969 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
1970 HitTestResult result(vPoint);
1971 doc->renderView()->hitTest(request, result);
1972
1973 Node* node = result.innerNode();
1974 // Wheel events should not dispatch to text nodes.
1975 if (node && node->isTextNode())
1976 node = NodeRenderingTraversal::parent(node);
1977
1978 bool isOverWidget;
1979 if (event.useLatchedEventNode()) {
1980 if (!m_latchedWheelEventNode) {
1981 m_latchedWheelEventNode = node;
1982 m_widgetIsLatched = result.isOverWidget();
1983 } else
1984 node = m_latchedWheelEventNode.get();
1985
1986 isOverWidget = m_widgetIsLatched;
1987 } else {
1988 if (m_latchedWheelEventNode)
1989 m_latchedWheelEventNode = nullptr;
1990 if (m_previousWheelScrolledNode)
1991 m_previousWheelScrolledNode = nullptr;
1992
1993 isOverWidget = result.isOverWidget();
1994 }
1995
1996 if (node) {
1997 // Figure out which view to send the event to.
1998 RenderObject* target = node->renderer();
1999
2000 if (isOverWidget && target && target->isWidget()) {
2001 Widget* widget = toRenderWidget(target)->widget();
2002 if (widget && passWheelEventToWidget(event, widget))
2003 RETURN_WHEEL_EVENT_HANDLED();
2004 }
2005
2006 if (node && !node->dispatchWheelEvent(event))
2007 RETURN_WHEEL_EVENT_HANDLED();
2008 }
2009
2010 // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
2011 view = m_frame->view();
2012 if (!view || !view->wheelEvent(event))
2013 return false;
2014
2015 RETURN_WHEEL_EVENT_HANDLED();
2016
2017 #undef RETURN_WHEEL_EVENT_HANDLED
2018 }
2019
defaultWheelEventHandler(Node * startNode,WheelEvent * wheelEvent)2020 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
2021 {
2022 if (!startNode || !wheelEvent)
2023 return;
2024
2025 // Ctrl + scrollwheel is reserved for triggering zoom in/out actions in Chromium.
2026 if (wheelEvent->ctrlKey())
2027 return;
2028
2029 Node* stopNode = m_previousWheelScrolledNode.get();
2030 ScrollGranularity granularity = wheelGranularityToScrollGranularity(wheelEvent->deltaMode());
2031
2032 // Break up into two scrolls if we need to. Diagonal movement on
2033 // a MacBook pro is an example of a 2-dimensional mouse wheel event (where both deltaX and deltaY can be set).
2034 if (scroll(ScrollRight, granularity, startNode, &stopNode, wheelEvent->deltaX(), roundedIntPoint(wheelEvent->absoluteLocation())))
2035 wheelEvent->setDefaultHandled();
2036
2037 if (scroll(ScrollDown, granularity, startNode, &stopNode, wheelEvent->deltaY(), roundedIntPoint(wheelEvent->absoluteLocation())))
2038 wheelEvent->setDefaultHandled();
2039
2040 if (!m_latchedWheelEventNode)
2041 m_previousWheelScrolledNode = stopNode;
2042 }
2043
handleGestureShowPress()2044 bool EventHandler::handleGestureShowPress()
2045 {
2046 m_lastShowPressTimestamp = WTF::currentTime();
2047
2048 FrameView* view = m_frame->view();
2049 if (!view)
2050 return false;
2051 if (ScrollAnimator* scrollAnimator = view->existingScrollAnimator())
2052 scrollAnimator->cancelAnimations();
2053 const FrameView::ScrollableAreaSet* areas = view->scrollableAreas();
2054 if (!areas)
2055 return false;
2056 for (FrameView::ScrollableAreaSet::const_iterator it = areas->begin(); it != areas->end(); ++it) {
2057 ScrollableArea* sa = *it;
2058 ScrollAnimator* animator = sa->scrollAnimator();
2059 if (animator)
2060 animator->cancelAnimations();
2061 }
2062 return false;
2063 }
2064
handleGestureEvent(const PlatformGestureEvent & gestureEvent)2065 bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
2066 {
2067 IntPoint adjustedPoint = gestureEvent.position();
2068 RefPtr<LocalFrame> subframe = nullptr;
2069 switch (gestureEvent.type()) {
2070 case PlatformEvent::GestureScrollBegin:
2071 case PlatformEvent::GestureScrollUpdate:
2072 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2073 case PlatformEvent::GestureScrollEnd:
2074 case PlatformEvent::GestureFlingStart:
2075 // Handle directly in main frame
2076 break;
2077
2078 case PlatformEvent::GestureTap:
2079 case PlatformEvent::GestureTapUnconfirmed:
2080 case PlatformEvent::GestureTapDown:
2081 case PlatformEvent::GestureShowPress:
2082 case PlatformEvent::GestureTapDownCancel:
2083 case PlatformEvent::GestureTwoFingerTap:
2084 case PlatformEvent::GestureLongPress:
2085 case PlatformEvent::GestureLongTap:
2086 case PlatformEvent::GesturePinchBegin:
2087 case PlatformEvent::GesturePinchEnd:
2088 case PlatformEvent::GesturePinchUpdate:
2089 adjustGesturePosition(gestureEvent, adjustedPoint);
2090 subframe = getSubFrameForGestureEvent(adjustedPoint, gestureEvent);
2091 if (subframe)
2092 return subframe->eventHandler().handleGestureEvent(gestureEvent);
2093 break;
2094
2095 default:
2096 ASSERT_NOT_REACHED();
2097 }
2098
2099 RefPtrWillBeRawPtr<Node> eventTarget = nullptr;
2100 RefPtr<Scrollbar> scrollbar;
2101 if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2102 || gestureEvent.type() == PlatformEvent::GestureScrollUpdate
2103 || gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation
2104 || gestureEvent.type() == PlatformEvent::GestureFlingStart) {
2105 scrollbar = m_scrollbarHandlingScrollGesture.get();
2106 eventTarget = m_scrollGestureHandlingNode.get();
2107 }
2108
2109 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent;
2110 double activeInterval = 0;
2111 bool shouldKeepActiveForMinInterval = false;
2112 if (gestureEvent.type() == PlatformEvent::GestureShowPress
2113 || gestureEvent.type() == PlatformEvent::GestureTapUnconfirmed) {
2114 hitType |= HitTestRequest::Active;
2115 } else if (gestureEvent.type() == PlatformEvent::GestureTapDownCancel) {
2116 hitType |= HitTestRequest::Release;
2117 // A TapDownCancel received when no element is active shouldn't really be changing hover state.
2118 if (!m_frame->document()->activeHoverElement())
2119 hitType |= HitTestRequest::ReadOnly;
2120 } else if (gestureEvent.type() == PlatformEvent::GestureTap) {
2121 hitType |= HitTestRequest::Release;
2122 // If the Tap is received very shortly after ShowPress, we want to
2123 // delay clearing of the active state so that it's visible to the user
2124 // for at least a couple of frames.
2125 activeInterval = WTF::currentTime() - m_lastShowPressTimestamp;
2126 shouldKeepActiveForMinInterval = m_lastShowPressTimestamp && activeInterval < minimumActiveInterval;
2127 if (shouldKeepActiveForMinInterval)
2128 hitType |= HitTestRequest::ReadOnly;
2129 }
2130 else
2131 hitType |= HitTestRequest::Active | HitTestRequest::ReadOnly;
2132
2133 if ((!scrollbar && !eventTarget) || !(hitType & HitTestRequest::ReadOnly)) {
2134 IntPoint hitTestPoint = m_frame->view()->windowToContents(adjustedPoint);
2135 HitTestResult result = hitTestResultAtPoint(hitTestPoint, hitType | HitTestRequest::AllowFrameScrollbars);
2136
2137 if (shouldKeepActiveForMinInterval) {
2138 m_lastDeferredTapElement = result.innerElement();
2139 m_activeIntervalTimer.startOneShot(minimumActiveInterval - activeInterval, FROM_HERE);
2140 }
2141
2142 eventTarget = result.targetNode();
2143 if (!scrollbar) {
2144 FrameView* view = m_frame->view();
2145 scrollbar = view ? view->scrollbarAtPoint(gestureEvent.position()) : 0;
2146 }
2147 if (!scrollbar)
2148 scrollbar = result.scrollbar();
2149 }
2150
2151 if (scrollbar) {
2152 bool eventSwallowed = scrollbar->gestureEvent(gestureEvent);
2153 if (gestureEvent.type() == PlatformEvent::GestureTapDown && eventSwallowed) {
2154 m_scrollbarHandlingScrollGesture = scrollbar;
2155 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd
2156 || gestureEvent.type() == PlatformEvent::GestureFlingStart
2157 || !eventSwallowed) {
2158 m_scrollbarHandlingScrollGesture = nullptr;
2159 }
2160
2161 if (eventSwallowed)
2162 return true;
2163 }
2164
2165 if (eventTarget) {
2166 bool eventSwallowed = false;
2167 if (handleScrollGestureOnResizer(eventTarget.get(), gestureEvent))
2168 eventSwallowed = true;
2169 else
2170 eventSwallowed = eventTarget->dispatchGestureEvent(gestureEvent);
2171 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin || gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2172 if (eventSwallowed)
2173 m_scrollGestureHandlingNode = eventTarget;
2174 }
2175
2176 if (eventSwallowed)
2177 return true;
2178 }
2179
2180 // FIXME: A more general scroll system (https://bugs.webkit.org/show_bug.cgi?id=80596) will
2181 // eliminate the need for this.
2182 TemporaryChange<PlatformEvent::Type> baseEventType(m_baseEventType, gestureEvent.type());
2183
2184 switch (gestureEvent.type()) {
2185 case PlatformEvent::GestureScrollBegin:
2186 return handleGestureScrollBegin(gestureEvent);
2187 case PlatformEvent::GestureScrollUpdate:
2188 case PlatformEvent::GestureScrollUpdateWithoutPropagation:
2189 return handleGestureScrollUpdate(gestureEvent);
2190 case PlatformEvent::GestureScrollEnd:
2191 return handleGestureScrollEnd(gestureEvent);
2192 case PlatformEvent::GestureTap:
2193 return handleGestureTap(gestureEvent, adjustedPoint);
2194 case PlatformEvent::GestureShowPress:
2195 return handleGestureShowPress();
2196 case PlatformEvent::GestureLongPress:
2197 return handleGestureLongPress(gestureEvent, adjustedPoint);
2198 case PlatformEvent::GestureLongTap:
2199 return handleGestureLongTap(gestureEvent, adjustedPoint);
2200 case PlatformEvent::GestureTwoFingerTap:
2201 return handleGestureTwoFingerTap(gestureEvent, adjustedPoint);
2202 case PlatformEvent::GestureTapDown:
2203 case PlatformEvent::GesturePinchBegin:
2204 case PlatformEvent::GesturePinchEnd:
2205 case PlatformEvent::GesturePinchUpdate:
2206 case PlatformEvent::GestureTapDownCancel:
2207 case PlatformEvent::GestureTapUnconfirmed:
2208 case PlatformEvent::GestureFlingStart:
2209 break;
2210 default:
2211 ASSERT_NOT_REACHED();
2212 }
2213
2214 return false;
2215 }
2216
handleGestureTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2217 bool EventHandler::handleGestureTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2218 {
2219 // FIXME: Refactor this code to not hit test multiple times. We use the adjusted position to ensure that the correct node is targeted by the later redundant hit tests.
2220
2221 unsigned modifierFlags = 0;
2222 if (gestureEvent.altKey())
2223 modifierFlags |= PlatformEvent::AltKey;
2224 if (gestureEvent.ctrlKey())
2225 modifierFlags |= PlatformEvent::CtrlKey;
2226 if (gestureEvent.metaKey())
2227 modifierFlags |= PlatformEvent::MetaKey;
2228 if (gestureEvent.shiftKey())
2229 modifierFlags |= PlatformEvent::ShiftKey;
2230 PlatformEvent::Modifiers modifiers = static_cast<PlatformEvent::Modifiers>(modifierFlags);
2231
2232 PlatformMouseEvent fakeMouseMove(adjustedPoint, gestureEvent.globalPosition(),
2233 NoButton, PlatformEvent::MouseMoved, /* clickCount */ 0,
2234 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2235 handleMouseMoveEvent(fakeMouseMove);
2236
2237 bool defaultPrevented = false;
2238 PlatformMouseEvent fakeMouseDown(adjustedPoint, gestureEvent.globalPosition(),
2239 LeftButton, PlatformEvent::MousePressed, gestureEvent.tapCount(),
2240 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2241 defaultPrevented |= handleMousePressEvent(fakeMouseDown);
2242
2243 PlatformMouseEvent fakeMouseUp(adjustedPoint, gestureEvent.globalPosition(),
2244 LeftButton, PlatformEvent::MouseReleased, gestureEvent.tapCount(),
2245 modifiers, PlatformMouseEvent::FromTouch, gestureEvent.timestamp());
2246 defaultPrevented |= handleMouseReleaseEvent(fakeMouseUp);
2247
2248 return defaultPrevented;
2249 }
2250
handleGestureLongPress(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2251 bool EventHandler::handleGestureLongPress(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2252 {
2253 m_longTapShouldInvokeContextMenu = false;
2254 if (m_frame->settings() && m_frame->settings()->touchDragDropEnabled() && m_frame->view()) {
2255 PlatformMouseEvent mouseDownEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2256 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2257 m_mouseDown = mouseDownEvent;
2258
2259 PlatformMouseEvent mouseDragEvent(adjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MouseMoved, 1,
2260 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), WTF::currentTime());
2261 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2262 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDragEvent);
2263 m_didStartDrag = false;
2264 m_mouseDownMayStartDrag = true;
2265 dragState().m_dragSrc = nullptr;
2266 m_mouseDownPos = m_frame->view()->windowToContents(mouseDragEvent.position());
2267 RefPtr<FrameView> protector(m_frame->view());
2268 handleDrag(mev, DontCheckDragHysteresis);
2269 if (m_didStartDrag) {
2270 m_longTapShouldInvokeContextMenu = true;
2271 return true;
2272 }
2273 }
2274 #if OS(ANDROID)
2275 bool shouldLongPressSelectWord = true;
2276 #else
2277 bool shouldLongPressSelectWord = m_frame->settings() && m_frame->settings()->touchEditingEnabled();
2278 #endif
2279 if (shouldLongPressSelectWord) {
2280 IntPoint hitTestPoint = m_frame->view()->windowToContents(gestureEvent.position());
2281 HitTestResult result = hitTestResultAtPoint(hitTestPoint);
2282 Node* innerNode = result.targetNode();
2283 if (!result.isLiveLink() && innerNode && (innerNode->isContentEditable() || innerNode->isTextNode())) {
2284 selectClosestWordFromHitTestResult(result, DontAppendTrailingWhitespace);
2285 if (m_frame->selection().isRange()) {
2286 focusDocumentView();
2287 return true;
2288 }
2289 }
2290 }
2291 return sendContextMenuEventForGesture(gestureEvent);
2292 }
2293
handleGestureLongTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2294 bool EventHandler::handleGestureLongTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2295 {
2296 #if !OS(ANDROID)
2297 if (m_longTapShouldInvokeContextMenu) {
2298 m_longTapShouldInvokeContextMenu = false;
2299 return sendContextMenuEventForGesture(gestureEvent);
2300 }
2301 #endif
2302 return false;
2303 }
2304
handleScrollGestureOnResizer(Node * eventTarget,const PlatformGestureEvent & gestureEvent)2305 bool EventHandler::handleScrollGestureOnResizer(Node* eventTarget, const PlatformGestureEvent& gestureEvent) {
2306 if (gestureEvent.type() == PlatformEvent::GestureScrollBegin) {
2307 RenderLayer* layer = eventTarget->renderer() ? eventTarget->renderer()->enclosingLayer() : 0;
2308 IntPoint p = m_frame->view()->windowToContents(gestureEvent.position());
2309 if (layer && layer->scrollableArea() && layer->scrollableArea()->isPointInResizeControl(p, ResizerForTouch)) {
2310 m_resizeScrollableArea = layer->scrollableArea();
2311 m_resizeScrollableArea->setInResizeMode(true);
2312 m_offsetFromResizeCorner = m_resizeScrollableArea->offsetFromResizeCorner(p);
2313 return true;
2314 }
2315 } else if (gestureEvent.type() == PlatformEvent::GestureScrollUpdate ||
2316 gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation) {
2317 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2318 m_resizeScrollableArea->resize(gestureEvent, m_offsetFromResizeCorner);
2319 return true;
2320 }
2321 } else if (gestureEvent.type() == PlatformEvent::GestureScrollEnd) {
2322 if (m_resizeScrollableArea && m_resizeScrollableArea->inResizeMode()) {
2323 m_resizeScrollableArea->setInResizeMode(false);
2324 m_resizeScrollableArea = 0;
2325 return false;
2326 }
2327 }
2328
2329 return false;
2330 }
2331
handleGestureTwoFingerTap(const PlatformGestureEvent & gestureEvent,const IntPoint & adjustedPoint)2332 bool EventHandler::handleGestureTwoFingerTap(const PlatformGestureEvent& gestureEvent, const IntPoint& adjustedPoint)
2333 {
2334 return sendContextMenuEventForGesture(gestureEvent);
2335 }
2336
passGestureEventToWidget(const PlatformGestureEvent & gestureEvent,Widget * widget)2337 bool EventHandler::passGestureEventToWidget(const PlatformGestureEvent& gestureEvent, Widget* widget)
2338 {
2339 if (!widget)
2340 return false;
2341
2342 if (!widget->isFrameView())
2343 return false;
2344
2345 return toFrameView(widget)->frame().eventHandler().handleGestureEvent(gestureEvent);
2346 }
2347
passGestureEventToWidgetIfPossible(const PlatformGestureEvent & gestureEvent,RenderObject * renderer)2348 bool EventHandler::passGestureEventToWidgetIfPossible(const PlatformGestureEvent& gestureEvent, RenderObject* renderer)
2349 {
2350 if (m_lastHitTestResultOverWidget && renderer && renderer->isWidget()) {
2351 Widget* widget = toRenderWidget(renderer)->widget();
2352 return widget && passGestureEventToWidget(gestureEvent, widget);
2353 }
2354 return false;
2355 }
2356
handleGestureScrollEnd(const PlatformGestureEvent & gestureEvent)2357 bool EventHandler::handleGestureScrollEnd(const PlatformGestureEvent& gestureEvent) {
2358 RefPtrWillBeRawPtr<Node> node = m_scrollGestureHandlingNode;
2359 clearGestureScrollNodes();
2360
2361 if (node)
2362 passGestureEventToWidgetIfPossible(gestureEvent, node->renderer());
2363
2364 return false;
2365 }
2366
handleGestureScrollBegin(const PlatformGestureEvent & gestureEvent)2367 bool EventHandler::handleGestureScrollBegin(const PlatformGestureEvent& gestureEvent)
2368 {
2369 Document* document = m_frame->document();
2370 if (!document->renderView())
2371 return false;
2372
2373 FrameView* view = m_frame->view();
2374 if (!view)
2375 return false;
2376
2377 LayoutPoint viewPoint = view->windowToContents(gestureEvent.position());
2378 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2379 HitTestResult result(viewPoint);
2380 document->renderView()->hitTest(request, result);
2381
2382 m_lastHitTestResultOverWidget = result.isOverWidget();
2383 m_scrollGestureHandlingNode = result.innerNode();
2384 m_previousGestureScrolledNode = nullptr;
2385
2386 // If there's no renderer on the node, send the event to the nearest ancestor with a renderer.
2387 // Needed for <option> and <optgroup> elements so we can touch scroll <select>s
2388 while (m_scrollGestureHandlingNode && !m_scrollGestureHandlingNode->renderer())
2389 m_scrollGestureHandlingNode = m_scrollGestureHandlingNode->parentOrShadowHostNode();
2390
2391 if (!m_scrollGestureHandlingNode)
2392 return false;
2393
2394 passGestureEventToWidgetIfPossible(gestureEvent, m_scrollGestureHandlingNode->renderer());
2395
2396 return true;
2397 }
2398
handleGestureScrollUpdate(const PlatformGestureEvent & gestureEvent)2399 bool EventHandler::handleGestureScrollUpdate(const PlatformGestureEvent& gestureEvent)
2400 {
2401 FloatSize delta(gestureEvent.deltaX(), gestureEvent.deltaY());
2402 if (delta.isZero())
2403 return false;
2404
2405 const float scaleFactor = m_frame->pageZoomFactor();
2406 delta.scale(1 / scaleFactor, 1 / scaleFactor);
2407
2408 Node* node = m_scrollGestureHandlingNode.get();
2409 if (!node)
2410 return sendScrollEventToView(gestureEvent, delta);
2411
2412 // Ignore this event if the targeted node does not have a valid renderer.
2413 RenderObject* renderer = node->renderer();
2414 if (!renderer)
2415 return false;
2416
2417 RefPtr<FrameView> protector(m_frame->view());
2418
2419 Node* stopNode = 0;
2420 bool scrollShouldNotPropagate = gestureEvent.type() == PlatformEvent::GestureScrollUpdateWithoutPropagation;
2421
2422 // Try to send the event to the correct view.
2423 if (passGestureEventToWidgetIfPossible(gestureEvent, renderer)) {
2424 if(scrollShouldNotPropagate)
2425 m_previousGestureScrolledNode = m_scrollGestureHandlingNode;
2426
2427 return true;
2428 }
2429
2430 if (scrollShouldNotPropagate)
2431 stopNode = m_previousGestureScrolledNode.get();
2432
2433 // First try to scroll the closest scrollable RenderBox ancestor of |node|.
2434 ScrollGranularity granularity = ScrollByPixel;
2435 bool horizontalScroll = scroll(ScrollLeft, granularity, node, &stopNode, delta.width());
2436 bool verticalScroll = scroll(ScrollUp, granularity, node, &stopNode, delta.height());
2437
2438 if (scrollShouldNotPropagate)
2439 m_previousGestureScrolledNode = stopNode;
2440
2441 if (horizontalScroll || verticalScroll) {
2442 setFrameWasScrolledByUser();
2443 return true;
2444 }
2445
2446 // Otherwise try to scroll the view.
2447 return sendScrollEventToView(gestureEvent, delta);
2448 }
2449
sendScrollEventToView(const PlatformGestureEvent & gestureEvent,const FloatSize & scaledDelta)2450 bool EventHandler::sendScrollEventToView(const PlatformGestureEvent& gestureEvent, const FloatSize& scaledDelta)
2451 {
2452 FrameView* view = m_frame->view();
2453 if (!view)
2454 return false;
2455
2456 const float tickDivisor = static_cast<float>(WheelEvent::TickMultiplier);
2457 IntPoint point(gestureEvent.position().x(), gestureEvent.position().y());
2458 IntPoint globalPoint(gestureEvent.globalPosition().x(), gestureEvent.globalPosition().y());
2459 PlatformWheelEvent syntheticWheelEvent(point, globalPoint,
2460 scaledDelta.width(), scaledDelta.height(),
2461 scaledDelta.width() / tickDivisor, scaledDelta.height() / tickDivisor,
2462 ScrollByPixelWheelEvent,
2463 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey());
2464 syntheticWheelEvent.setHasPreciseScrollingDeltas(true);
2465
2466 bool scrolledFrame = view->wheelEvent(syntheticWheelEvent);
2467 if (scrolledFrame)
2468 setFrameWasScrolledByUser();
2469
2470 return scrolledFrame;
2471 }
2472
getSubFrameForGestureEvent(const IntPoint & touchAdjustedPoint,const PlatformGestureEvent & gestureEvent)2473 LocalFrame* EventHandler::getSubFrameForGestureEvent(const IntPoint& touchAdjustedPoint, const PlatformGestureEvent& gestureEvent)
2474 {
2475 PlatformMouseEvent mouseDown(touchAdjustedPoint, gestureEvent.globalPosition(), LeftButton, PlatformEvent::MousePressed, 1,
2476 gestureEvent.shiftKey(), gestureEvent.ctrlKey(), gestureEvent.altKey(), gestureEvent.metaKey(), gestureEvent.timestamp());
2477 HitTestRequest request(HitTestRequest::ReadOnly);
2478 MouseEventWithHitTestResults mev = prepareMouseEvent(request, mouseDown);
2479 return subframeForHitTestResult(mev);
2480 }
2481
clearGestureScrollNodes()2482 void EventHandler::clearGestureScrollNodes()
2483 {
2484 m_scrollGestureHandlingNode = nullptr;
2485 m_previousGestureScrolledNode = nullptr;
2486 }
2487
isScrollbarHandlingGestures() const2488 bool EventHandler::isScrollbarHandlingGestures() const
2489 {
2490 return m_scrollbarHandlingScrollGesture.get();
2491 }
2492
shouldApplyTouchAdjustment(const PlatformGestureEvent & event) const2493 bool EventHandler::shouldApplyTouchAdjustment(const PlatformGestureEvent& event) const
2494 {
2495 if (m_frame->settings() && !m_frame->settings()->touchAdjustmentEnabled())
2496 return false;
2497 return !event.area().isEmpty();
2498 }
2499
bestClickableNodeForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntPoint & targetPoint,Node * & targetNode)2500 bool EventHandler::bestClickableNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2501 {
2502 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2503 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2504
2505 // If the touch is over a scrollbar, don't adjust the touch point since touch adjustment only takes into account
2506 // DOM nodes so a touch over a scrollbar will be adjusted towards nearby nodes. This leads to things like textarea
2507 // scrollbars being untouchable.
2508 if (result.scrollbar())
2509 return false;
2510
2511 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2512 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2513 copyToVector(result.rectBasedTestResult(), nodes);
2514
2515 // FIXME: Should be able to handle targetNode being a shadow DOM node to avoid performing uncessary hit tests
2516 // in the case where further processing on the node is required. Returning the shadow ancestor prevents a
2517 // regression in touchadjustment/html-label.html. Some refinement is required to testing/internals to
2518 // handle targetNode being a shadow DOM node.
2519
2520 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2521 // FIXME: targetNode and success are only used by Internals functions. We should
2522 // instead have dedicated test methods so we only do this work in tests.
2523 bool success = findBestClickableCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> > (nodes));
2524 if (success && targetNode)
2525 targetNode = targetNode->deprecatedShadowAncestorNode();
2526 return success;
2527 }
2528
bestContextMenuNodeForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntPoint & targetPoint,Node * & targetNode)2529 bool EventHandler::bestContextMenuNodeForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntPoint& targetPoint, Node*& targetNode)
2530 {
2531 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2532 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active, touchRadius);
2533
2534 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2535 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2536 copyToVector(result.rectBasedTestResult(), nodes);
2537
2538 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2539 return findBestContextMenuCandidate(targetNode, targetPoint, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> >(nodes));
2540 }
2541
bestZoomableAreaForTouchPoint(const IntPoint & touchCenter,const IntSize & touchRadius,IntRect & targetArea,Node * & targetNode)2542 bool EventHandler::bestZoomableAreaForTouchPoint(const IntPoint& touchCenter, const IntSize& touchRadius, IntRect& targetArea, Node*& targetNode)
2543 {
2544 IntPoint hitTestPoint = m_frame->view()->windowToContents(touchCenter);
2545 HitTestResult result = hitTestResultAtPoint(hitTestPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, touchRadius);
2546
2547 IntRect touchRect(touchCenter - touchRadius, touchRadius + touchRadius);
2548 WillBeHeapVector<RefPtrWillBeMember<Node>, 11> nodes;
2549 copyToVector(result.rectBasedTestResult(), nodes);
2550
2551 // FIXME: the explicit Vector conversion copies into a temporary and is wasteful.
2552 return findBestZoomableArea(targetNode, targetArea, touchCenter, touchRect, WillBeHeapVector<RefPtrWillBeMember<Node> >(nodes));
2553 }
2554
adjustGesturePosition(const PlatformGestureEvent & gestureEvent,IntPoint & adjustedPoint)2555 void EventHandler::adjustGesturePosition(const PlatformGestureEvent& gestureEvent, IntPoint& adjustedPoint)
2556 {
2557 if (!shouldApplyTouchAdjustment(gestureEvent))
2558 return;
2559
2560 Node* targetNode = 0;
2561 switch (gestureEvent.type()) {
2562 case PlatformEvent::GestureTap:
2563 case PlatformEvent::GestureTapUnconfirmed:
2564 case PlatformEvent::GestureTapDown:
2565 case PlatformEvent::GestureShowPress:
2566 bestClickableNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2567 break;
2568 case PlatformEvent::GestureLongPress:
2569 case PlatformEvent::GestureLongTap:
2570 case PlatformEvent::GestureTwoFingerTap:
2571 bestContextMenuNodeForTouchPoint(gestureEvent.position(), IntSize(gestureEvent.area().width() / 2, gestureEvent.area().height() / 2), adjustedPoint, targetNode);
2572 break;
2573 default:
2574 // FIXME: Implement handling for other types as needed.
2575 ASSERT_NOT_REACHED();
2576 }
2577 }
2578
sendContextMenuEvent(const PlatformMouseEvent & event)2579 bool EventHandler::sendContextMenuEvent(const PlatformMouseEvent& event)
2580 {
2581 Document* doc = m_frame->document();
2582 FrameView* v = m_frame->view();
2583 if (!v)
2584 return false;
2585
2586 // Clear mouse press state to avoid initiating a drag while context menu is up.
2587 m_mousePressed = false;
2588 LayoutPoint viewportPos = v->windowToContents(event.position());
2589 HitTestRequest request(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2590 MouseEventWithHitTestResults mev = doc->prepareMouseEvent(request, viewportPos, event);
2591
2592 if (!m_frame->selection().contains(viewportPos)
2593 && !mev.scrollbar()
2594 // FIXME: In the editable case, word selection sometimes selects content that isn't underneath the mouse.
2595 // If the selection is non-editable, we do word selection to make it easier to use the contextual menu items
2596 // available for text selections. But only if we're above text.
2597 && (m_frame->selection().isContentEditable() || (mev.targetNode() && mev.targetNode()->isTextNode()))) {
2598 m_mouseDownMayStartSelect = true; // context menu events are always allowed to perform a selection
2599
2600 if (mev.hitTestResult().isMisspelled())
2601 selectClosestMisspellingFromMouseEvent(mev);
2602 else if (m_frame->editor().behavior().shouldSelectOnContextualMenuClick())
2603 selectClosestWordOrLinkFromMouseEvent(mev);
2604 }
2605
2606 return !dispatchMouseEvent(EventTypeNames::contextmenu, mev.targetNode(), 0, event, false);
2607 }
2608
sendContextMenuEventForKey()2609 bool EventHandler::sendContextMenuEventForKey()
2610 {
2611 FrameView* view = m_frame->view();
2612 if (!view)
2613 return false;
2614
2615 Document* doc = m_frame->document();
2616 if (!doc)
2617 return false;
2618
2619 // Clear mouse press state to avoid initiating a drag while context menu is up.
2620 m_mousePressed = false;
2621
2622 static const int kContextMenuMargin = 1;
2623
2624 #if OS(WIN)
2625 int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
2626 #else
2627 int rightAligned = 0;
2628 #endif
2629 IntPoint location;
2630
2631 Element* focusedElement = doc->focusedElement();
2632 FrameSelection& selection = m_frame->selection();
2633 Position start = selection.selection().start();
2634 bool shouldTranslateToRootView = true;
2635
2636 if (start.deprecatedNode() && (selection.rootEditableElement() || selection.isRange())) {
2637 RefPtrWillBeRawPtr<Range> selectionRange = selection.toNormalizedRange();
2638 IntRect firstRect = m_frame->editor().firstRectForRange(selectionRange.get());
2639
2640 int x = rightAligned ? firstRect.maxX() : firstRect.x();
2641 // In a multiline edit, firstRect.maxY() would endup on the next line, so -1.
2642 int y = firstRect.maxY() ? firstRect.maxY() - 1 : 0;
2643 location = IntPoint(x, y);
2644 } else if (focusedElement) {
2645 IntRect clippedRect = focusedElement->boundsInRootViewSpace();
2646 location = IntPoint(clippedRect.center());
2647 } else {
2648 location = IntPoint(
2649 rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
2650 kContextMenuMargin);
2651 shouldTranslateToRootView = false;
2652 }
2653
2654 m_frame->view()->setCursor(pointerCursor());
2655
2656 IntPoint position = shouldTranslateToRootView ? view->contentsToRootView(location) : location;
2657 IntPoint globalPosition = view->hostWindow()->rootViewToScreen(IntRect(position, IntSize())).location();
2658
2659 Node* targetNode = doc->focusedElement();
2660 if (!targetNode)
2661 targetNode = doc;
2662
2663 // Use the focused node as the target for hover and active.
2664 HitTestResult result(position);
2665 result.setInnerNode(targetNode);
2666 doc->updateHoverActiveState(HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, result.innerElement());
2667
2668 // The contextmenu event is a mouse event even when invoked using the keyboard.
2669 // This is required for web compatibility.
2670
2671 #if OS(WIN)
2672 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2673 #else
2674 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2675 #endif
2676
2677 PlatformMouseEvent mouseEvent(position, globalPosition, RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2678
2679 handleMousePressEvent(mouseEvent);
2680 return sendContextMenuEvent(mouseEvent);
2681 }
2682
sendContextMenuEventForGesture(const PlatformGestureEvent & event)2683 bool EventHandler::sendContextMenuEventForGesture(const PlatformGestureEvent& event)
2684 {
2685 #if OS(WIN)
2686 PlatformEvent::Type eventType = PlatformEvent::MouseReleased;
2687 #else
2688 PlatformEvent::Type eventType = PlatformEvent::MousePressed;
2689 #endif
2690
2691 IntPoint adjustedPoint = event.position();
2692 adjustGesturePosition(event, adjustedPoint);
2693 PlatformMouseEvent mouseEvent(adjustedPoint, event.globalPosition(), RightButton, eventType, 1, false, false, false, false, WTF::currentTime());
2694 // To simulate right-click behavior, we send a right mouse down and then
2695 // context menu event.
2696 handleMousePressEvent(mouseEvent);
2697 return sendContextMenuEvent(mouseEvent);
2698 // We do not need to send a corresponding mouse release because in case of
2699 // right-click, the context menu takes capture and consumes all events.
2700 }
2701
scheduleHoverStateUpdate()2702 void EventHandler::scheduleHoverStateUpdate()
2703 {
2704 if (!m_hoverTimer.isActive())
2705 m_hoverTimer.startOneShot(0, FROM_HERE);
2706 }
2707
scheduleCursorUpdate()2708 void EventHandler::scheduleCursorUpdate()
2709 {
2710 if (!m_cursorUpdateTimer.isActive())
2711 m_cursorUpdateTimer.startOneShot(cursorUpdateInterval, FROM_HERE);
2712 }
2713
dispatchFakeMouseMoveEventSoon()2714 void EventHandler::dispatchFakeMouseMoveEventSoon()
2715 {
2716 if (m_mousePressed)
2717 return;
2718
2719 if (m_mousePositionIsUnknown)
2720 return;
2721
2722 Settings* settings = m_frame->settings();
2723 if (settings && !settings->deviceSupportsMouse())
2724 return;
2725
2726 // If the content has ever taken longer than fakeMouseMoveShortInterval we
2727 // reschedule the timer and use a longer time. This will cause the content
2728 // to receive these moves only after the user is done scrolling, reducing
2729 // pauses during the scroll.
2730 if (m_maxMouseMovedDuration > fakeMouseMoveShortInterval) {
2731 if (m_fakeMouseMoveEventTimer.isActive())
2732 m_fakeMouseMoveEventTimer.stop();
2733 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveLongInterval, FROM_HERE);
2734 } else {
2735 if (!m_fakeMouseMoveEventTimer.isActive())
2736 m_fakeMouseMoveEventTimer.startOneShot(fakeMouseMoveShortInterval, FROM_HERE);
2737 }
2738 }
2739
dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad & quad)2740 void EventHandler::dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad& quad)
2741 {
2742 FrameView* view = m_frame->view();
2743 if (!view)
2744 return;
2745
2746 if (!quad.containsPoint(view->windowToContents(m_lastKnownMousePosition)))
2747 return;
2748
2749 dispatchFakeMouseMoveEventSoon();
2750 }
2751
fakeMouseMoveEventTimerFired(Timer<EventHandler> * timer)2752 void EventHandler::fakeMouseMoveEventTimerFired(Timer<EventHandler>* timer)
2753 {
2754 ASSERT_UNUSED(timer, timer == &m_fakeMouseMoveEventTimer);
2755 ASSERT(!m_mousePressed);
2756
2757 Settings* settings = m_frame->settings();
2758 if (settings && !settings->deviceSupportsMouse())
2759 return;
2760
2761 FrameView* view = m_frame->view();
2762 if (!view)
2763 return;
2764
2765 if (!m_frame->page() || !m_frame->page()->focusController().isActive())
2766 return;
2767
2768 // Don't dispatch a synthetic mouse move event if the mouse cursor is not visible to the user.
2769 if (!isCursorVisible())
2770 return;
2771
2772 bool shiftKey;
2773 bool ctrlKey;
2774 bool altKey;
2775 bool metaKey;
2776 PlatformKeyboardEvent::getCurrentModifierState(shiftKey, ctrlKey, altKey, metaKey);
2777 PlatformMouseEvent fakeMouseMoveEvent(m_lastKnownMousePosition, m_lastKnownMouseGlobalPosition, NoButton, PlatformEvent::MouseMoved, 0, shiftKey, ctrlKey, altKey, metaKey, currentTime());
2778 handleMouseMoveEvent(fakeMouseMoveEvent);
2779 }
2780
cancelFakeMouseMoveEvent()2781 void EventHandler::cancelFakeMouseMoveEvent()
2782 {
2783 m_fakeMouseMoveEventTimer.stop();
2784 }
2785
isCursorVisible() const2786 bool EventHandler::isCursorVisible() const
2787 {
2788 return m_frame->page()->isCursorVisible();
2789 }
2790
setResizingFrameSet(HTMLFrameSetElement * frameSet)2791 void EventHandler::setResizingFrameSet(HTMLFrameSetElement* frameSet)
2792 {
2793 m_frameSetBeingResized = frameSet;
2794 }
2795
resizeScrollableAreaDestroyed()2796 void EventHandler::resizeScrollableAreaDestroyed()
2797 {
2798 ASSERT(m_resizeScrollableArea);
2799 m_resizeScrollableArea = 0;
2800 }
2801
hoverTimerFired(Timer<EventHandler> *)2802 void EventHandler::hoverTimerFired(Timer<EventHandler>*)
2803 {
2804 m_hoverTimer.stop();
2805
2806 ASSERT(m_frame);
2807 ASSERT(m_frame->document());
2808
2809 if (RenderView* renderer = m_frame->contentRenderer()) {
2810 if (FrameView* view = m_frame->view()) {
2811 HitTestRequest request(HitTestRequest::Move | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
2812 HitTestResult result(view->windowToContents(m_lastKnownMousePosition));
2813 renderer->hitTest(request, result);
2814 m_frame->document()->updateHoverActiveState(request, result.innerElement());
2815 }
2816 }
2817 }
2818
activeIntervalTimerFired(Timer<EventHandler> *)2819 void EventHandler::activeIntervalTimerFired(Timer<EventHandler>*)
2820 {
2821 m_activeIntervalTimer.stop();
2822
2823 if (m_frame
2824 && m_frame->document()
2825 && m_lastDeferredTapElement) {
2826 // FIXME: Enable condition when http://crbug.com/226842 lands
2827 // m_lastDeferredTapElement.get() == m_frame->document()->activeElement()
2828 HitTestRequest request(HitTestRequest::TouchEvent | HitTestRequest::Release);
2829 m_frame->document()->updateHoverActiveState(request, m_lastDeferredTapElement.get());
2830 }
2831 m_lastDeferredTapElement = nullptr;
2832 }
2833
notifyElementActivated()2834 void EventHandler::notifyElementActivated()
2835 {
2836 // Since another element has been set to active, stop current timer and clear reference.
2837 if (m_activeIntervalTimer.isActive())
2838 m_activeIntervalTimer.stop();
2839 m_lastDeferredTapElement = nullptr;
2840 }
2841
handleAccessKey(const PlatformKeyboardEvent & evt)2842 bool EventHandler::handleAccessKey(const PlatformKeyboardEvent& evt)
2843 {
2844 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
2845 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
2846 // lower case variants are present in a document, the correct element is matched based on Shift key state.
2847 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
2848 ASSERT(!(accessKeyModifiers() & PlatformEvent::ShiftKey));
2849 if ((evt.modifiers() & ~PlatformEvent::ShiftKey) != accessKeyModifiers())
2850 return false;
2851 String key = evt.unmodifiedText();
2852 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
2853 if (!elem)
2854 return false;
2855 elem->accessKeyAction(false);
2856 return true;
2857 }
2858
isKeyEventAllowedInFullScreen(FullscreenElementStack * fullscreen,const PlatformKeyboardEvent & keyEvent) const2859 bool EventHandler::isKeyEventAllowedInFullScreen(FullscreenElementStack* fullscreen, const PlatformKeyboardEvent& keyEvent) const
2860 {
2861 if (fullscreen->webkitFullScreenKeyboardInputAllowed())
2862 return true;
2863
2864 if (keyEvent.type() == PlatformKeyboardEvent::Char) {
2865 if (keyEvent.text().length() != 1)
2866 return false;
2867 UChar character = keyEvent.text()[0];
2868 return character == ' ';
2869 }
2870
2871 int keyCode = keyEvent.windowsVirtualKeyCode();
2872 return (keyCode >= VK_BACK && keyCode <= VK_CAPITAL)
2873 || (keyCode >= VK_SPACE && keyCode <= VK_DELETE)
2874 || (keyCode >= VK_OEM_1 && keyCode <= VK_OEM_PLUS)
2875 || (keyCode >= VK_MULTIPLY && keyCode <= VK_OEM_8);
2876 }
2877
keyEvent(const PlatformKeyboardEvent & initialKeyEvent)2878 bool EventHandler::keyEvent(const PlatformKeyboardEvent& initialKeyEvent)
2879 {
2880 RefPtr<FrameView> protector(m_frame->view());
2881
2882 ASSERT(m_frame->document());
2883 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(*m_frame->document())) {
2884 if (fullscreen->webkitIsFullScreen() && !isKeyEventAllowedInFullScreen(fullscreen, initialKeyEvent))
2885 return false;
2886 }
2887
2888 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
2889 capsLockStateMayHaveChanged();
2890
2891 #if OS(WIN)
2892 if (panScrollInProgress()) {
2893 // If a key is pressed while the panScroll is in progress then we want to stop
2894 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
2895 stopAutoscroll();
2896
2897 // If we were in panscroll mode, we swallow the key event
2898 return true;
2899 }
2900 #endif
2901
2902 // Check for cases where we are too early for events -- possible unmatched key up
2903 // from pressing return in the location bar.
2904 RefPtrWillBeRawPtr<Node> node = eventTargetNodeForDocument(m_frame->document());
2905 if (!node)
2906 return false;
2907
2908 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
2909
2910 // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
2911 // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
2912 // with access keys. Then we dispatch keydown, but suppress its default handling.
2913 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
2914 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
2915 bool matchedAnAccessKey = false;
2916 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
2917 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
2918
2919 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
2920 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char)
2921 return !node->dispatchKeyEvent(initialKeyEvent);
2922
2923 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
2924 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
2925 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
2926 RefPtrWillBeRawPtr<KeyboardEvent> keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
2927 if (matchedAnAccessKey)
2928 keydown->setDefaultPrevented(true);
2929 keydown->setTarget(node);
2930
2931 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) {
2932 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2933 // If frame changed as a result of keydown dispatch, then return true to avoid sending a subsequent keypress message to the new frame.
2934 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2935 return keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2936 }
2937
2938 node->dispatchEvent(keydown, IGNORE_EXCEPTION);
2939 // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
2940 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
2941 bool keydownResult = keydown->defaultHandled() || keydown->defaultPrevented() || changedFocusedFrame;
2942 if (keydownResult)
2943 return keydownResult;
2944
2945 // Focus may have changed during keydown handling, so refetch node.
2946 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
2947 node = eventTargetNodeForDocument(m_frame->document());
2948 if (!node)
2949 return false;
2950
2951 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
2952 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
2953 if (keyPressEvent.text().isEmpty())
2954 return keydownResult;
2955 RefPtrWillBeRawPtr<KeyboardEvent> keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
2956 keypress->setTarget(node);
2957 if (keydownResult)
2958 keypress->setDefaultPrevented(true);
2959 node->dispatchEvent(keypress, IGNORE_EXCEPTION);
2960
2961 return keydownResult || keypress->defaultPrevented() || keypress->defaultHandled();
2962 }
2963
focusDirectionForKey(const AtomicString & keyIdentifier)2964 static FocusType focusDirectionForKey(const AtomicString& keyIdentifier)
2965 {
2966 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down", AtomicString::ConstructFromLiteral));
2967 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up", AtomicString::ConstructFromLiteral));
2968 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left", AtomicString::ConstructFromLiteral));
2969 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right", AtomicString::ConstructFromLiteral));
2970
2971 FocusType retVal = FocusTypeNone;
2972
2973 if (keyIdentifier == Down)
2974 retVal = FocusTypeDown;
2975 else if (keyIdentifier == Up)
2976 retVal = FocusTypeUp;
2977 else if (keyIdentifier == Left)
2978 retVal = FocusTypeLeft;
2979 else if (keyIdentifier == Right)
2980 retVal = FocusTypeRight;
2981
2982 return retVal;
2983 }
2984
defaultKeyboardEventHandler(KeyboardEvent * event)2985 void EventHandler::defaultKeyboardEventHandler(KeyboardEvent* event)
2986 {
2987 if (event->type() == EventTypeNames::keydown) {
2988 m_frame->editor().handleKeyboardEvent(event);
2989 if (event->defaultHandled())
2990 return;
2991 if (event->keyIdentifier() == "U+0009")
2992 defaultTabEventHandler(event);
2993 else if (event->keyIdentifier() == "U+0008")
2994 defaultBackspaceEventHandler(event);
2995 else if (event->keyIdentifier() == "U+001B")
2996 defaultEscapeEventHandler(event);
2997 else {
2998 FocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
2999 if (type != FocusTypeNone)
3000 defaultArrowEventHandler(type, event);
3001 }
3002 }
3003 if (event->type() == EventTypeNames::keypress) {
3004 m_frame->editor().handleKeyboardEvent(event);
3005 if (event->defaultHandled())
3006 return;
3007 if (event->charCode() == ' ')
3008 defaultSpaceEventHandler(event);
3009 }
3010 }
3011
dragHysteresisExceeded(const FloatPoint & floatDragViewportLocation) const3012 bool EventHandler::dragHysteresisExceeded(const FloatPoint& floatDragViewportLocation) const
3013 {
3014 return dragHysteresisExceeded(flooredIntPoint(floatDragViewportLocation));
3015 }
3016
dragHysteresisExceeded(const IntPoint & dragViewportLocation) const3017 bool EventHandler::dragHysteresisExceeded(const IntPoint& dragViewportLocation) const
3018 {
3019 FrameView* view = m_frame->view();
3020 if (!view)
3021 return false;
3022 IntPoint dragLocation = view->windowToContents(dragViewportLocation);
3023 IntSize delta = dragLocation - m_mouseDownPos;
3024
3025 int threshold = GeneralDragHysteresis;
3026 switch (dragState().m_dragType) {
3027 case DragSourceActionSelection:
3028 threshold = TextDragHysteresis;
3029 break;
3030 case DragSourceActionImage:
3031 threshold = ImageDragHysteresis;
3032 break;
3033 case DragSourceActionLink:
3034 threshold = LinkDragHysteresis;
3035 break;
3036 case DragSourceActionDHTML:
3037 break;
3038 case DragSourceActionNone:
3039 ASSERT_NOT_REACHED();
3040 }
3041
3042 return abs(delta.width()) >= threshold || abs(delta.height()) >= threshold;
3043 }
3044
freeClipboard()3045 void EventHandler::freeClipboard()
3046 {
3047 if (dragState().m_dragClipboard) {
3048 dragState().m_dragClipboard->clearDragImage();
3049 dragState().m_dragClipboard->setAccessPolicy(ClipboardNumb);
3050 }
3051 }
3052
dragSourceEndedAt(const PlatformMouseEvent & event,DragOperation operation)3053 void EventHandler::dragSourceEndedAt(const PlatformMouseEvent& event, DragOperation operation)
3054 {
3055 // Send a hit test request so that RenderLayer gets a chance to update the :hover and :active pseudoclasses.
3056 HitTestRequest request(HitTestRequest::Release | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent);
3057 prepareMouseEvent(request, event);
3058
3059 if (dragState().m_dragSrc) {
3060 dragState().m_dragClipboard->setDestinationOperation(operation);
3061 // for now we don't care if event handler cancels default behavior, since there is none
3062 dispatchDragSrcEvent(EventTypeNames::dragend, event);
3063 }
3064 freeClipboard();
3065 dragState().m_dragSrc = nullptr;
3066 // In case the drag was ended due to an escape key press we need to ensure
3067 // that consecutive mousemove events don't reinitiate the drag and drop.
3068 m_mouseDownMayStartDrag = false;
3069 }
3070
updateDragStateAfterEditDragIfNeeded(Element * rootEditableElement)3071 void EventHandler::updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement)
3072 {
3073 // If inserting the dragged contents removed the drag source, we still want to fire dragend at the root editble element.
3074 if (dragState().m_dragSrc && !dragState().m_dragSrc->inDocument())
3075 dragState().m_dragSrc = rootEditableElement;
3076 }
3077
3078 // returns if we should continue "default processing", i.e., whether eventhandler canceled
dispatchDragSrcEvent(const AtomicString & eventType,const PlatformMouseEvent & event)3079 bool EventHandler::dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent& event)
3080 {
3081 return !dispatchDragEvent(eventType, dragState().m_dragSrc.get(), event, dragState().m_dragClipboard.get());
3082 }
3083
handleDrag(const MouseEventWithHitTestResults & event,CheckDragHysteresis checkDragHysteresis)3084 bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDragHysteresis checkDragHysteresis)
3085 {
3086 ASSERT(event.event().type() == PlatformEvent::MouseMoved);
3087 // Callers must protect the reference to FrameView, since this function may dispatch DOM
3088 // events, causing page/FrameView to go away.
3089 ASSERT(m_frame);
3090 ASSERT(m_frame->view());
3091 if (!m_frame->page())
3092 return false;
3093
3094 if (event.event().button() != LeftButton || event.event().type() != PlatformEvent::MouseMoved) {
3095 // If we allowed the other side of the bridge to handle a drag
3096 // last time, then m_mousePressed might still be set. So we
3097 // clear it now to make sure the next move after a drag
3098 // doesn't look like a drag.
3099 m_mousePressed = false;
3100 return false;
3101 }
3102
3103 if (m_mouseDownMayStartDrag) {
3104 HitTestRequest request(HitTestRequest::ReadOnly);
3105 HitTestResult result(m_mouseDownPos);
3106 m_frame->contentRenderer()->hitTest(request, result);
3107 Node* node = result.innerNode();
3108 if (node) {
3109 DragController::SelectionDragPolicy selectionDragPolicy = event.event().timestamp() - m_mouseDownTimestamp < TextDragDelay
3110 ? DragController::DelayedSelectionDragResolution
3111 : DragController::ImmediateSelectionDragResolution;
3112 dragState().m_dragSrc = m_frame->page()->dragController().draggableNode(m_frame, node, m_mouseDownPos, selectionDragPolicy, dragState().m_dragType);
3113 } else {
3114 dragState().m_dragSrc = nullptr;
3115 }
3116
3117 if (!dragState().m_dragSrc)
3118 m_mouseDownMayStartDrag = false; // no element is draggable
3119 }
3120
3121 if (!m_mouseDownMayStartDrag)
3122 return !mouseDownMayStartSelect() && !m_mouseDownMayStartAutoscroll;
3123
3124 // We are starting a text/image/url drag, so the cursor should be an arrow
3125 // FIXME <rdar://7577595>: Custom cursors aren't supported during drag and drop (default to pointer).
3126 m_frame->view()->setCursor(pointerCursor());
3127
3128 if (checkDragHysteresis == ShouldCheckDragHysteresis && !dragHysteresisExceeded(event.event().position()))
3129 return true;
3130
3131 // Once we're past the hysteresis point, we don't want to treat this gesture as a click
3132 invalidateClick();
3133
3134 if (!tryStartDrag(event)) {
3135 // Something failed to start the drag, clean up.
3136 freeClipboard();
3137 dragState().m_dragSrc = nullptr;
3138 }
3139
3140 m_mouseDownMayStartDrag = false;
3141 // Whether or not the drag actually started, no more default handling (like selection).
3142 return true;
3143 }
3144
tryStartDrag(const MouseEventWithHitTestResults & event)3145 bool EventHandler::tryStartDrag(const MouseEventWithHitTestResults& event)
3146 {
3147 freeClipboard(); // would only happen if we missed a dragEnd. Do it anyway, just
3148 // to make sure it gets numbified
3149 dragState().m_dragClipboard = createDraggingClipboard();
3150
3151 // Check to see if this a DOM based drag, if it is get the DOM specified drag
3152 // image and offset
3153 if (dragState().m_dragType == DragSourceActionDHTML) {
3154 if (RenderObject* renderer = dragState().m_dragSrc->renderer()) {
3155 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), UseTransforms);
3156 IntSize delta = m_mouseDownPos - roundedIntPoint(absPos);
3157 dragState().m_dragClipboard->setDragImageElement(dragState().m_dragSrc.get(), IntPoint(delta));
3158 } else {
3159 // The renderer has disappeared, this can happen if the onStartDrag handler has hidden
3160 // the element in some way. In this case we just kill the drag.
3161 return false;
3162 }
3163 }
3164
3165 DragController& dragController = m_frame->page()->dragController();
3166 if (!dragController.populateDragClipboard(m_frame, dragState(), m_mouseDownPos))
3167 return false;
3168 m_mouseDownMayStartDrag = dispatchDragSrcEvent(EventTypeNames::dragstart, m_mouseDown)
3169 && !m_frame->selection().isInPasswordField();
3170
3171 // Invalidate clipboard here against anymore pasteboard writing for security. The drag
3172 // image can still be changed as we drag, but not the pasteboard data.
3173 dragState().m_dragClipboard->setAccessPolicy(ClipboardImageWritable);
3174
3175 if (m_mouseDownMayStartDrag) {
3176 // Dispatching the event could cause Page to go away. Make sure it's still valid before trying to use DragController.
3177 m_didStartDrag = m_frame->page() && dragController.startDrag(m_frame, dragState(), event.event(), m_mouseDownPos);
3178 // FIXME: This seems pretty useless now. The gesture code uses this as a signal for
3179 // whether or not the drag started, but perhaps it can simply use the return value from
3180 // handleDrag(), even though it doesn't mean exactly the same thing.
3181 if (m_didStartDrag)
3182 return true;
3183 // Drag was canned at the last minute - we owe m_dragSrc a DRAGEND event
3184 dispatchDragSrcEvent(EventTypeNames::dragend, event.event());
3185 }
3186
3187 return false;
3188 }
3189
handleTextInputEvent(const String & text,Event * underlyingEvent,TextEventInputType inputType)3190 bool EventHandler::handleTextInputEvent(const String& text, Event* underlyingEvent, TextEventInputType inputType)
3191 {
3192 // Platforms should differentiate real commands like selectAll from text input in disguise (like insertNewline),
3193 // and avoid dispatching text input events from keydown default handlers.
3194 ASSERT(!underlyingEvent || !underlyingEvent->isKeyboardEvent() || toKeyboardEvent(underlyingEvent)->type() == EventTypeNames::keypress);
3195
3196 if (!m_frame)
3197 return false;
3198
3199 EventTarget* target;
3200 if (underlyingEvent)
3201 target = underlyingEvent->target();
3202 else
3203 target = eventTargetNodeForDocument(m_frame->document());
3204 if (!target)
3205 return false;
3206
3207 RefPtrWillBeRawPtr<TextEvent> event = TextEvent::create(m_frame->domWindow(), text, inputType);
3208 event->setUnderlyingEvent(underlyingEvent);
3209
3210 target->dispatchEvent(event, IGNORE_EXCEPTION);
3211 return event->defaultHandled();
3212 }
3213
defaultTextInputEventHandler(TextEvent * event)3214 void EventHandler::defaultTextInputEventHandler(TextEvent* event)
3215 {
3216 if (m_frame->editor().handleTextEvent(event))
3217 event->setDefaultHandled();
3218 }
3219
defaultSpaceEventHandler(KeyboardEvent * event)3220 void EventHandler::defaultSpaceEventHandler(KeyboardEvent* event)
3221 {
3222 ASSERT(event->type() == EventTypeNames::keypress);
3223
3224 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3225 return;
3226
3227 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
3228 if (scroll(direction, ScrollByPage)) {
3229 event->setDefaultHandled();
3230 return;
3231 }
3232
3233 FrameView* view = m_frame->view();
3234 if (!view)
3235 return;
3236
3237 if (view->scroll(direction, ScrollByPage))
3238 event->setDefaultHandled();
3239 }
3240
defaultBackspaceEventHandler(KeyboardEvent * event)3241 void EventHandler::defaultBackspaceEventHandler(KeyboardEvent* event)
3242 {
3243 ASSERT(event->type() == EventTypeNames::keydown);
3244
3245 if (event->ctrlKey() || event->metaKey() || event->altKey() || event->altGraphKey())
3246 return;
3247
3248 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
3249 return;
3250
3251 Page* page = m_frame->page();
3252 if (!page || !page->mainFrame()->isLocalFrame())
3253 return;
3254 bool handledEvent = page->deprecatedLocalMainFrame()->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
3255 if (handledEvent)
3256 event->setDefaultHandled();
3257 }
3258
defaultArrowEventHandler(FocusType focusType,KeyboardEvent * event)3259 void EventHandler::defaultArrowEventHandler(FocusType focusType, KeyboardEvent* event)
3260 {
3261 ASSERT(event->type() == EventTypeNames::keydown);
3262
3263 if (event->ctrlKey() || event->metaKey() || event->altGraphKey() || event->shiftKey())
3264 return;
3265
3266 Page* page = m_frame->page();
3267 if (!page)
3268 return;
3269
3270 if (!isSpatialNavigationEnabled(m_frame))
3271 return;
3272
3273 // Arrows and other possible directional navigation keys can be used in design
3274 // mode editing.
3275 if (m_frame->document()->inDesignMode())
3276 return;
3277
3278 if (page->focusController().advanceFocus(focusType))
3279 event->setDefaultHandled();
3280 }
3281
defaultTabEventHandler(KeyboardEvent * event)3282 void EventHandler::defaultTabEventHandler(KeyboardEvent* event)
3283 {
3284 ASSERT(event->type() == EventTypeNames::keydown);
3285
3286 // We should only advance focus on tabs if no special modifier keys are held down.
3287 if (event->ctrlKey() || event->metaKey() || event->altGraphKey())
3288 return;
3289
3290 Page* page = m_frame->page();
3291 if (!page)
3292 return;
3293 if (!page->tabKeyCyclesThroughElements())
3294 return;
3295
3296 FocusType focusType = event->shiftKey() ? FocusTypeBackward : FocusTypeForward;
3297
3298 // Tabs can be used in design mode editing.
3299 if (m_frame->document()->inDesignMode())
3300 return;
3301
3302 if (page->focusController().advanceFocus(focusType))
3303 event->setDefaultHandled();
3304 }
3305
defaultEscapeEventHandler(KeyboardEvent * event)3306 void EventHandler::defaultEscapeEventHandler(KeyboardEvent* event)
3307 {
3308 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
3309 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
3310 }
3311
capsLockStateMayHaveChanged()3312 void EventHandler::capsLockStateMayHaveChanged()
3313 {
3314 if (Element* element = m_frame->document()->focusedElement()) {
3315 if (RenderObject* r = element->renderer()) {
3316 if (r->isTextField())
3317 toRenderTextControlSingleLine(r)->capsLockStateMayHaveChanged();
3318 }
3319 }
3320 }
3321
setFrameWasScrolledByUser()3322 void EventHandler::setFrameWasScrolledByUser()
3323 {
3324 if (FrameView* view = m_frame->view())
3325 view->setWasScrolledByUser(true);
3326 }
3327
passMousePressEventToScrollbar(MouseEventWithHitTestResults & mev)3328 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults& mev)
3329 {
3330 // First try to use the frame scrollbar.
3331 FrameView* view = m_frame->view();
3332 Scrollbar* scrollbar = view ? view->scrollbarAtPoint(mev.event().position()) : 0;
3333
3334 // Then try the scrollbar in the hit test.
3335 if (!scrollbar)
3336 scrollbar = mev.scrollbar();
3337
3338 updateLastScrollbarUnderMouse(scrollbar, true);
3339
3340 if (!scrollbar || !scrollbar->enabled())
3341 return false;
3342 setFrameWasScrolledByUser();
3343 scrollbar->mouseDown(mev.event());
3344 return true;
3345 }
3346
3347 // If scrollbar (under mouse) is different from last, send a mouse exited. Set
3348 // last to scrollbar if setLast is true; else set last to 0.
updateLastScrollbarUnderMouse(Scrollbar * scrollbar,bool setLast)3349 void EventHandler::updateLastScrollbarUnderMouse(Scrollbar* scrollbar, bool setLast)
3350 {
3351 if (m_lastScrollbarUnderMouse != scrollbar) {
3352 // Send mouse exited to the old scrollbar.
3353 if (m_lastScrollbarUnderMouse)
3354 m_lastScrollbarUnderMouse->mouseExited();
3355
3356 // Send mouse entered if we're setting a new scrollbar.
3357 if (scrollbar && setLast)
3358 scrollbar->mouseEntered();
3359
3360 m_lastScrollbarUnderMouse = setLast ? scrollbar : 0;
3361 }
3362 }
3363
eventNameForTouchPointState(PlatformTouchPoint::State state)3364 static const AtomicString& eventNameForTouchPointState(PlatformTouchPoint::State state)
3365 {
3366 switch (state) {
3367 case PlatformTouchPoint::TouchReleased:
3368 return EventTypeNames::touchend;
3369 case PlatformTouchPoint::TouchCancelled:
3370 return EventTypeNames::touchcancel;
3371 case PlatformTouchPoint::TouchPressed:
3372 return EventTypeNames::touchstart;
3373 case PlatformTouchPoint::TouchMoved:
3374 return EventTypeNames::touchmove;
3375 case PlatformTouchPoint::TouchStationary:
3376 // TouchStationary state is not converted to touch events, so fall through to assert.
3377 default:
3378 ASSERT_NOT_REACHED();
3379 return emptyAtom;
3380 }
3381 }
3382
hitTestResultInFrame(LocalFrame * frame,const LayoutPoint & point,HitTestRequest::HitTestRequestType hitType)3383 HitTestResult EventHandler::hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& point, HitTestRequest::HitTestRequestType hitType)
3384 {
3385 HitTestResult result(point);
3386
3387 if (!frame || !frame->contentRenderer())
3388 return result;
3389 if (frame->view()) {
3390 IntRect rect = frame->view()->visibleContentRect();
3391 if (!rect.contains(roundedIntPoint(point)))
3392 return result;
3393 }
3394 frame->contentRenderer()->hitTest(HitTestRequest(hitType), result);
3395 return result;
3396 }
3397
handleTouchEvent(const PlatformTouchEvent & event)3398 bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
3399 {
3400 TRACE_EVENT0("webkit", "EventHandler::handleTouchEvent");
3401
3402 const Vector<PlatformTouchPoint>& points = event.touchPoints();
3403
3404 unsigned i;
3405 bool freshTouchEvents = true;
3406 bool allTouchReleased = true;
3407 for (i = 0; i < points.size(); ++i) {
3408 const PlatformTouchPoint& point = points[i];
3409 if (point.state() != PlatformTouchPoint::TouchPressed)
3410 freshTouchEvents = false;
3411 if (point.state() != PlatformTouchPoint::TouchReleased && point.state() != PlatformTouchPoint::TouchCancelled)
3412 allTouchReleased = false;
3413 }
3414 if (freshTouchEvents) {
3415 // Ideally we'd ASSERT !m_touchSequenceDocument here since we should
3416 // have cleared the active document when we saw the last release. But we
3417 // have some tests that violate this, ClusterFuzz could trigger it, and
3418 // there may be cases where the browser doesn't reliably release all
3419 // touches. http://crbug.com/345372 tracks this.
3420 m_touchSequenceDocument.clear();
3421 m_touchSequenceUserGestureToken.clear();
3422 }
3423
3424 OwnPtr<UserGestureIndicator> gestureIndicator;
3425
3426 if (m_touchSequenceUserGestureToken)
3427 gestureIndicator = adoptPtr(new UserGestureIndicator(m_touchSequenceUserGestureToken.release()));
3428 else
3429 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProcessingUserGesture));
3430
3431 m_touchSequenceUserGestureToken = gestureIndicator->currentToken();
3432
3433 ASSERT(m_frame->view());
3434 if (m_touchSequenceDocument && (!m_touchSequenceDocument->frame() || !m_touchSequenceDocument->frame()->view())) {
3435 // If the active touch document has no frame or view, it's probably being destroyed
3436 // so we can't dispatch events.
3437 return false;
3438 }
3439
3440 // First do hit tests for any new touch points.
3441 for (i = 0; i < points.size(); ++i) {
3442 const PlatformTouchPoint& point = points[i];
3443
3444 // Touch events implicitly capture to the touched node, and don't change
3445 // active/hover states themselves (Gesture events do). So we only need
3446 // to hit-test on touchstart, and it can be read-only.
3447 if (point.state() == PlatformTouchPoint::TouchPressed) {
3448 HitTestRequest::HitTestRequestType hitType = HitTestRequest::TouchEvent | HitTestRequest::ReadOnly | HitTestRequest::Active;
3449 LayoutPoint pagePoint = roundedLayoutPoint(m_frame->view()->windowToContents(point.pos()));
3450 HitTestResult result;
3451 if (!m_touchSequenceDocument) {
3452 result = hitTestResultAtPoint(pagePoint, hitType);
3453 } else if (m_touchSequenceDocument->frame()) {
3454 LayoutPoint framePoint = roundedLayoutPoint(m_touchSequenceDocument->frame()->view()->windowToContents(point.pos()));
3455 result = hitTestResultInFrame(m_touchSequenceDocument->frame(), framePoint, hitType);
3456 } else
3457 continue;
3458
3459 Node* node = result.innerNode();
3460 if (!node)
3461 continue;
3462
3463 // Touch events should not go to text nodes
3464 if (node->isTextNode())
3465 node = NodeRenderingTraversal::parent(node);
3466
3467 if (!m_touchSequenceDocument) {
3468 // Keep track of which document should receive all touch events
3469 // in the active sequence. This must be a single document to
3470 // ensure we don't leak Nodes between documents.
3471 m_touchSequenceDocument = &(result.innerNode()->document());
3472 ASSERT(m_touchSequenceDocument->frame()->view());
3473 }
3474
3475 // Ideally we'd ASSERT(!m_targetForTouchID.contains(point.id())
3476 // since we shouldn't get a touchstart for a touch that's already
3477 // down. However EventSender allows this to be violated and there's
3478 // some tests that take advantage of it. There may also be edge
3479 // cases in the browser where this happens.
3480 // See http://crbug.com/345372.
3481 m_targetForTouchID.set(point.id(), node);
3482
3483 TouchAction effectiveTouchAction = computeEffectiveTouchAction(*node);
3484 if (effectiveTouchAction != TouchActionAuto)
3485 m_frame->page()->chrome().client().setTouchAction(effectiveTouchAction);
3486 }
3487 }
3488
3489 m_touchPressed = !allTouchReleased;
3490
3491 // If there's no document receiving touch events, or no handlers on the
3492 // document set to receive the events, then we can skip all the rest of
3493 // this work.
3494 if (!m_touchSequenceDocument || !m_touchSequenceDocument->hasTouchEventHandlers() || !m_touchSequenceDocument->frame()) {
3495 if (allTouchReleased) {
3496 m_touchSequenceDocument.clear();
3497 m_touchSequenceUserGestureToken.clear();
3498 }
3499 return false;
3500 }
3501
3502 // Build up the lists to use for the 'touches', 'targetTouches' and
3503 // 'changedTouches' attributes in the JS event. See
3504 // http://www.w3.org/TR/touch-events/#touchevent-interface for how these
3505 // lists fit together.
3506
3507 // Holds the complete set of touches on the screen.
3508 RefPtrWillBeRawPtr<TouchList> touches = TouchList::create();
3509
3510 // A different view on the 'touches' list above, filtered and grouped by
3511 // event target. Used for the 'targetTouches' list in the JS event.
3512 typedef WillBeHeapHashMap<EventTarget*, RefPtrWillBeMember<TouchList> > TargetTouchesHeapMap;
3513 TargetTouchesHeapMap touchesByTarget;
3514
3515 // Array of touches per state, used to assemble the 'changedTouches' list.
3516 typedef WillBeHeapHashSet<RefPtrWillBeMember<EventTarget> > EventTargetSet;
3517 struct {
3518 // The touches corresponding to the particular change state this struct
3519 // instance represents.
3520 RefPtrWillBeMember<TouchList> m_touches;
3521 // Set of targets involved in m_touches.
3522 EventTargetSet m_targets;
3523 } changedTouches[PlatformTouchPoint::TouchStateEnd];
3524
3525 for (i = 0; i < points.size(); ++i) {
3526 const PlatformTouchPoint& point = points[i];
3527 PlatformTouchPoint::State pointState = point.state();
3528 RefPtrWillBeRawPtr<EventTarget> touchTarget = nullptr;
3529
3530 if (pointState == PlatformTouchPoint::TouchReleased || pointState == PlatformTouchPoint::TouchCancelled) {
3531 // The target should be the original target for this touch, so get
3532 // it from the hashmap. As it's a release or cancel we also remove
3533 // it from the map.
3534 touchTarget = m_targetForTouchID.take(point.id());
3535 } else {
3536 // No hittest is performed on move or stationary, since the target
3537 // is not allowed to change anyway.
3538 touchTarget = m_targetForTouchID.get(point.id());
3539 }
3540
3541 LocalFrame* targetFrame = 0;
3542 bool knownTarget = false;
3543 if (touchTarget) {
3544 Document& doc = touchTarget->toNode()->document();
3545 // If the target node has moved to a new document while it was being touched,
3546 // we can't send events to the new document because that could leak nodes
3547 // from one document to another. See http://crbug.com/394339.
3548 if (&doc == m_touchSequenceDocument.get()) {
3549 targetFrame = doc.frame();
3550 knownTarget = true;
3551 }
3552 }
3553 if (!knownTarget) {
3554 // If we don't have a target registered for the point it means we've
3555 // missed our opportunity to do a hit test for it (due to some
3556 // optimization that prevented blink from ever seeing the
3557 // touchstart), or that the touch started outside the active touch
3558 // sequence document. We should still include the touch in the
3559 // Touches list reported to the application (eg. so it can
3560 // differentiate between a one and two finger gesture), but we won't
3561 // actually dispatch any events for it. Set the target to the
3562 // Document so that there's some valid node here. Perhaps this
3563 // should really be LocalDOMWindow, but in all other cases the target of
3564 // a Touch is a Node so using the window could be a breaking change.
3565 // Since we know there was no handler invoked, the specific target
3566 // should be completely irrelevant to the application.
3567 // FIXME: Oilpan: We can remove the following .get() if EventTarget
3568 // is on-heap.
3569 touchTarget = m_touchSequenceDocument.get();
3570 targetFrame = m_touchSequenceDocument->frame();
3571 }
3572 ASSERT(targetFrame);
3573
3574 // pagePoint should always be relative to the target elements
3575 // containing frame.
3576 FloatPoint pagePoint = targetFrame->view()->windowToContents(point.pos());
3577
3578 float scaleFactor = 1.0f / targetFrame->pageZoomFactor();
3579
3580 FloatPoint adjustedPagePoint = pagePoint.scaledBy(scaleFactor);
3581 FloatSize adjustedRadius = point.radius().scaledBy(scaleFactor);
3582
3583 RefPtrWillBeRawPtr<Touch> touch = Touch::create(
3584 targetFrame, touchTarget.get(), point.id(), point.screenPos(), adjustedPagePoint, adjustedRadius, point.rotationAngle(), point.force());
3585
3586 // Ensure this target's touch list exists, even if it ends up empty, so
3587 // it can always be passed to TouchEvent::Create below.
3588 TargetTouchesHeapMap::iterator targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3589 if (targetTouchesIterator == touchesByTarget.end()) {
3590 touchesByTarget.set(touchTarget.get(), TouchList::create());
3591 targetTouchesIterator = touchesByTarget.find(touchTarget.get());
3592 }
3593
3594 // touches and targetTouches should only contain information about
3595 // touches still on the screen, so if this point is released or
3596 // cancelled it will only appear in the changedTouches list.
3597 if (pointState != PlatformTouchPoint::TouchReleased && pointState != PlatformTouchPoint::TouchCancelled) {
3598 touches->append(touch);
3599 targetTouchesIterator->value->append(touch);
3600 }
3601
3602 // Now build up the correct list for changedTouches.
3603 // Note that any touches that are in the TouchStationary state (e.g. if
3604 // the user had several points touched but did not move them all) should
3605 // never be in the changedTouches list so we do not handle them
3606 // explicitly here. See https://bugs.webkit.org/show_bug.cgi?id=37609
3607 // for further discussion about the TouchStationary state.
3608 if (pointState != PlatformTouchPoint::TouchStationary && knownTarget) {
3609 ASSERT(pointState < PlatformTouchPoint::TouchStateEnd);
3610 if (!changedTouches[pointState].m_touches)
3611 changedTouches[pointState].m_touches = TouchList::create();
3612 changedTouches[pointState].m_touches->append(touch);
3613 changedTouches[pointState].m_targets.add(touchTarget);
3614 }
3615 }
3616 if (allTouchReleased) {
3617 m_touchSequenceDocument.clear();
3618 m_touchSequenceUserGestureToken.clear();
3619 }
3620
3621 // Now iterate the changedTouches list and m_targets within it, sending
3622 // events to the targets as required.
3623 bool swallowedEvent = false;
3624 for (unsigned state = 0; state != PlatformTouchPoint::TouchStateEnd; ++state) {
3625 if (!changedTouches[state].m_touches)
3626 continue;
3627
3628 const AtomicString& stateName(eventNameForTouchPointState(static_cast<PlatformTouchPoint::State>(state)));
3629 const EventTargetSet& targetsForState = changedTouches[state].m_targets;
3630 for (EventTargetSet::const_iterator it = targetsForState.begin(); it != targetsForState.end(); ++it) {
3631 EventTarget* touchEventTarget = it->get();
3632 RefPtrWillBeRawPtr<TouchEvent> touchEvent = TouchEvent::create(
3633 touches.get(), touchesByTarget.get(touchEventTarget), changedTouches[state].m_touches.get(),
3634 stateName, touchEventTarget->toNode()->document().domWindow(),
3635 event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.cancelable());
3636 touchEventTarget->toNode()->dispatchTouchEvent(touchEvent.get());
3637 swallowedEvent = swallowedEvent || touchEvent->defaultPrevented() || touchEvent->defaultHandled();
3638 }
3639 }
3640
3641 return swallowedEvent;
3642 }
3643
intersectTouchAction(TouchAction action1,TouchAction action2)3644 TouchAction EventHandler::intersectTouchAction(TouchAction action1, TouchAction action2)
3645 {
3646 if (action1 == TouchActionNone || action2 == TouchActionNone)
3647 return TouchActionNone;
3648 if (action1 == TouchActionAuto)
3649 return action2;
3650 if (action2 == TouchActionAuto)
3651 return action1;
3652 if (!(action1 & action2))
3653 return TouchActionNone;
3654 return action1 & action2;
3655 }
3656
computeEffectiveTouchAction(const Node & node)3657 TouchAction EventHandler::computeEffectiveTouchAction(const Node& node)
3658 {
3659 // Optimization to minimize risk of this new feature (behavior should be identical
3660 // since there's no way to get non-default touch-action values).
3661 if (!RuntimeEnabledFeatures::cssTouchActionEnabled())
3662 return TouchActionAuto;
3663
3664 // Start by permitting all actions, then walk the elements supporting
3665 // touch-action from the target node up to the nearest scrollable ancestor
3666 // and exclude any prohibited actions.
3667 TouchAction effectiveTouchAction = TouchActionAuto;
3668 for (const Node* curNode = &node; curNode; curNode = NodeRenderingTraversal::parent(curNode)) {
3669 if (RenderObject* renderer = curNode->renderer()) {
3670 if (renderer->supportsTouchAction()) {
3671 TouchAction action = renderer->style()->touchAction();
3672 effectiveTouchAction = intersectTouchAction(action, effectiveTouchAction);
3673 if (effectiveTouchAction == TouchActionNone)
3674 break;
3675 }
3676
3677 // If we've reached an ancestor that supports a touch action, search no further.
3678 if (renderer->isBox() && toRenderBox(renderer)->scrollsOverflow())
3679 break;
3680 }
3681 }
3682 return effectiveTouchAction;
3683 }
3684
setLastKnownMousePosition(const PlatformMouseEvent & event)3685 void EventHandler::setLastKnownMousePosition(const PlatformMouseEvent& event)
3686 {
3687 m_mousePositionIsUnknown = false;
3688 m_lastKnownMousePosition = event.position();
3689 m_lastKnownMouseGlobalPosition = event.globalPosition();
3690 }
3691
passMousePressEventToSubframe(MouseEventWithHitTestResults & mev,LocalFrame * subframe)3692 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3693 {
3694 // If we're clicking into a frame that is selected, the frame will appear
3695 // greyed out even though we're clicking on the selection. This looks
3696 // really strange (having the whole frame be greyed out), so we deselect the
3697 // selection.
3698 IntPoint p = m_frame->view()->windowToContents(mev.event().position());
3699 if (m_frame->selection().contains(p)) {
3700 VisiblePosition visiblePos(
3701 mev.targetNode()->renderer()->positionForPoint(mev.localPoint()));
3702 VisibleSelection newSelection(visiblePos);
3703 m_frame->selection().setSelection(newSelection);
3704 }
3705
3706 subframe->eventHandler().handleMousePressEvent(mev.event());
3707 return true;
3708 }
3709
passMouseMoveEventToSubframe(MouseEventWithHitTestResults & mev,LocalFrame * subframe,HitTestResult * hoveredNode)3710 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe, HitTestResult* hoveredNode)
3711 {
3712 if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
3713 return false;
3714 subframe->eventHandler().handleMouseMoveOrLeaveEvent(mev.event(), hoveredNode);
3715 return true;
3716 }
3717
passMouseReleaseEventToSubframe(MouseEventWithHitTestResults & mev,LocalFrame * subframe)3718 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, LocalFrame* subframe)
3719 {
3720 subframe->eventHandler().handleMouseReleaseEvent(mev.event());
3721 return true;
3722 }
3723
passWheelEventToWidget(const PlatformWheelEvent & wheelEvent,Widget * widget)3724 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget* widget)
3725 {
3726 // We can sometimes get a null widget! EventHandlerMac handles a null
3727 // widget by returning false, so we do the same.
3728 if (!widget)
3729 return false;
3730
3731 // If not a FrameView, then probably a plugin widget. Those will receive
3732 // the event via an EventTargetNode dispatch when this returns false.
3733 if (!widget->isFrameView())
3734 return false;
3735
3736 return toFrameView(widget)->frame().eventHandler().handleWheelEvent(wheelEvent);
3737 }
3738
passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults & event)3739 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
3740 {
3741 // Figure out which view to send the event to.
3742 if (!event.targetNode() || !event.targetNode()->renderer() || !event.targetNode()->renderer()->isWidget())
3743 return false;
3744 return false;
3745 }
3746
createDraggingClipboard() const3747 PassRefPtrWillBeRawPtr<Clipboard> EventHandler::createDraggingClipboard() const
3748 {
3749 return Clipboard::create(Clipboard::DragAndDrop, ClipboardWritable, DataObject::create());
3750 }
3751
focusDocumentView()3752 void EventHandler::focusDocumentView()
3753 {
3754 Page* page = m_frame->page();
3755 if (!page)
3756 return;
3757 page->focusController().focusDocumentView(m_frame);
3758 }
3759
accessKeyModifiers()3760 unsigned EventHandler::accessKeyModifiers()
3761 {
3762 #if OS(MACOSX)
3763 return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
3764 #else
3765 return PlatformEvent::AltKey;
3766 #endif
3767 }
3768
3769 } // namespace WebCore
3770