1/*
2 * Copyright (C) 2006-2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef EventHandler_h
27#define EventHandler_h
28
29#include "Cursor.h"
30#include "DragActions.h"
31#include "FocusDirection.h"
32#include "HitTestRequest.h"
33#include "LayoutPoint.h"
34#include "PlatformMouseEvent.h"
35#include "PlatformWheelEvent.h"
36#include "ScrollTypes.h"
37#include "TextEventInputType.h"
38#include "TextGranularity.h"
39#include "Timer.h"
40#include "WheelEventDeltaTracker.h"
41#include <memory>
42#include <wtf/Forward.h>
43#include <wtf/RefPtr.h>
44
45#if PLATFORM(IOS)
46#ifdef __OBJC__
47@class WebEvent;
48@class WAKView;
49#include "WAKAppKitStubs.h"
50#else
51class WebEvent;
52#endif
53#endif // PLATFORM(IOS)
54
55#if PLATFORM(COCOA) && !defined(__OBJC__)
56class NSView;
57#endif
58
59#if ENABLE(TOUCH_EVENTS)
60#include <wtf/HashMap.h>
61#endif
62
63#if ENABLE(IOS_TOUCH_EVENTS)
64#include <wtf/HashSet.h>
65#include <wtf/Vector.h>
66#endif
67
68namespace WebCore {
69
70class AutoscrollController;
71class ContainerNode;
72class DataTransfer;
73class Document;
74class Element;
75class Event;
76class EventTarget;
77class FloatPoint;
78class FloatQuad;
79class Frame;
80class HTMLFrameSetElement;
81class HitTestRequest;
82class HitTestResult;
83class KeyboardEvent;
84class MouseEventWithHitTestResults;
85class Node;
86class OptionalCursor;
87class PlatformKeyboardEvent;
88class PlatformTouchEvent;
89class PlatformWheelEvent;
90class RenderBox;
91class RenderElement;
92class RenderLayer;
93class RenderWidget;
94class ScrollableArea;
95class SVGElementInstance;
96class Scrollbar;
97class TextEvent;
98class Touch;
99class TouchEvent;
100class VisibleSelection;
101class WheelEvent;
102class Widget;
103
104struct DragState;
105
106#if ENABLE(DRAG_SUPPORT)
107extern const int LinkDragHysteresis;
108extern const int ImageDragHysteresis;
109extern const int TextDragHysteresis;
110extern const int GeneralDragHysteresis;
111#endif // ENABLE(DRAG_SUPPORT)
112
113#if ENABLE(IOS_GESTURE_EVENTS)
114extern const float GestureUnknown;
115#endif
116
117enum AppendTrailingWhitespace { ShouldAppendTrailingWhitespace, DontAppendTrailingWhitespace };
118enum CheckDragHysteresis { ShouldCheckDragHysteresis, DontCheckDragHysteresis };
119
120class EventHandler {
121    WTF_MAKE_NONCOPYABLE(EventHandler);
122    WTF_MAKE_FAST_ALLOCATED;
123public:
124    explicit EventHandler(Frame&);
125    ~EventHandler();
126
127    void clear();
128    void nodeWillBeRemoved(Node*);
129
130#if ENABLE(DRAG_SUPPORT)
131    void updateSelectionForMouseDrag();
132#endif
133
134#if ENABLE(PAN_SCROLLING)
135    void didPanScrollStart();
136    void didPanScrollStop();
137    void startPanScrolling(RenderElement*);
138#endif
139
140    void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
141    RenderBox* autoscrollRenderer() const;
142    void updateAutoscrollRenderer();
143    bool autoscrollInProgress() const;
144    bool mouseDownWasInSubframe() const { return m_mouseDownWasInSubframe; }
145    bool panScrollInProgress() const;
146
147    void dispatchFakeMouseMoveEventSoon();
148    void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
149
150    HitTestResult hitTestResultAtPoint(const LayoutPoint&,
151        HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent,
152        const LayoutSize& padding = LayoutSize());
153
154    bool mousePressed() const { return m_mousePressed; }
155    Node* mousePressNode() const { return m_mousePressNode.get(); }
156
157    void setCapturingMouseEventsElement(PassRefPtr<Element>); // A caller is responsible for resetting capturing element to 0.
158
159#if ENABLE(DRAG_SUPPORT)
160    bool updateDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
161    void cancelDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
162    bool performDragAndDrop(const PlatformMouseEvent&, DataTransfer*);
163    void updateDragStateAfterEditDragIfNeeded(Element* rootEditableElement);
164#endif
165
166    void scheduleHoverStateUpdate();
167#if ENABLE(CURSOR_SUPPORT)
168    void scheduleCursorUpdate();
169#endif
170
171    void setResizingFrameSet(HTMLFrameSetElement*);
172
173    void resizeLayerDestroyed();
174
175    IntPoint lastKnownMousePosition() const;
176    Cursor currentMouseCursor() const { return m_currentMouseCursor; }
177
178    static Frame* subframeForTargetNode(Node*);
179    static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
180
181    bool scrollOverflow(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
182    bool scrollRecursively(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
183    bool logicalScrollRecursively(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
184
185    bool tabsToLinks(KeyboardEvent*) const;
186    bool tabsToAllFormControls(KeyboardEvent*) const;
187
188    bool mouseMoved(const PlatformMouseEvent&);
189    bool passMouseMovedEventToScrollbars(const PlatformMouseEvent&);
190
191    void lostMouseCapture();
192
193    bool handleMousePressEvent(const PlatformMouseEvent&);
194    bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0, bool onlyUpdateScrollbars = false);
195    bool handleMouseReleaseEvent(const PlatformMouseEvent&);
196    bool handleWheelEvent(const PlatformWheelEvent&);
197    void defaultWheelEventHandler(Node*, WheelEvent*);
198    bool handlePasteGlobalSelection(const PlatformMouseEvent&);
199
200    void platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>& eventTarget, RefPtr<ContainerNode>& scrollableContainer, ScrollableArea*&, bool& isOverWidget);
201    void platformRecordWheelEvent(const PlatformWheelEvent&);
202    bool platformCompleteWheelEvent(const PlatformWheelEvent&, Element* eventTarget, ContainerNode* scrollableContainer, ScrollableArea*);
203    bool platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode* scrollableContainer);
204
205#if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
206    typedef Vector<RefPtr<Touch>> TouchArray;
207    typedef HashMap<EventTarget*, TouchArray*> EventTargetTouchMap;
208    typedef HashSet<RefPtr<EventTarget>> EventTargetSet;
209#endif
210
211#if ENABLE(IOS_TOUCH_EVENTS)
212    bool dispatchTouchEvent(const PlatformTouchEvent&, const AtomicString&, const EventTargetTouchMap&, float, float);
213#endif
214
215#if ENABLE(IOS_GESTURE_EVENTS)
216    bool dispatchGestureEvent(const PlatformTouchEvent&, const AtomicString&, const EventTargetSet&, float, float);
217#endif
218
219#if PLATFORM(IOS)
220    void defaultTouchEventHandler(Node*, TouchEvent*);
221#endif
222
223#if ENABLE(CONTEXT_MENUS)
224    bool sendContextMenuEvent(const PlatformMouseEvent&);
225    bool sendContextMenuEventForKey();
226#endif
227
228    void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
229
230    bool needsKeyboardEventDisambiguationQuirks() const;
231
232    static unsigned accessKeyModifiers();
233    bool handleAccessKey(const PlatformKeyboardEvent&);
234    bool keyEvent(const PlatformKeyboardEvent&);
235    void defaultKeyboardEventHandler(KeyboardEvent*);
236
237    void handleKeyboardSelectionMovementForAccessibility(KeyboardEvent*);
238
239    bool handleTextInputEvent(const String& text, Event* underlyingEvent = 0, TextEventInputType = TextEventInputKeyboard);
240    void defaultTextInputEventHandler(TextEvent*);
241
242#if ENABLE(DRAG_SUPPORT)
243    bool eventMayStartDrag(const PlatformMouseEvent&) const;
244
245    void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
246#endif
247
248    void focusDocumentView();
249
250    void capsLockStateMayHaveChanged(); // Only called by FrameSelection
251
252    void sendScrollEvent(); // Ditto
253
254#if PLATFORM(COCOA) && defined(__OBJC__)
255#if !PLATFORM(IOS)
256    void mouseDown(NSEvent *);
257    void mouseDragged(NSEvent *);
258    void mouseUp(NSEvent *);
259    void mouseMoved(NSEvent *);
260    bool keyEvent(NSEvent *);
261    bool wheelEvent(NSEvent *);
262#else
263    void mouseDown(WebEvent *);
264    void mouseUp(WebEvent *);
265    void mouseMoved(WebEvent *);
266    bool keyEvent(WebEvent *);
267    bool wheelEvent(WebEvent *);
268#endif
269
270#if ENABLE(IOS_TOUCH_EVENTS)
271    void touchEvent(WebEvent *);
272#endif
273
274#if !PLATFORM(IOS)
275    void passMouseMovedEventToScrollbars(NSEvent *);
276
277    void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent);
278#endif
279
280#if !PLATFORM(IOS)
281    void setActivationEventNumber(int num) { m_activationEventNumber = num; }
282
283    static NSEvent *currentNSEvent();
284#else
285    static WebEvent *currentEvent();
286#endif // !PLATFORM(IOS)
287#endif // PLATFORM(COCOA) && defined(__OBJC__)
288
289#if PLATFORM(IOS)
290    void invalidateClick();
291#endif
292
293#if ENABLE(TOUCH_EVENTS)
294    bool handleTouchEvent(const PlatformTouchEvent&);
295#endif
296
297    bool useHandCursor(Node*, bool isOverLink, bool shiftKey);
298    void updateCursor();
299
300    bool isHandlingWheelEvent() const { return m_isHandlingWheelEvent; }
301
302private:
303#if ENABLE(DRAG_SUPPORT)
304    static DragState& dragState();
305    static const double TextDragDelay;
306
307    PassRefPtr<DataTransfer> createDraggingDataTransfer() const;
308#endif // ENABLE(DRAG_SUPPORT)
309
310    bool eventActivatedView(const PlatformMouseEvent&) const;
311    bool updateSelectionForMouseDownDispatchingSelectStart(Node*, const VisibleSelection&, TextGranularity);
312    void selectClosestWordFromHitTestResult(const HitTestResult&, AppendTrailingWhitespace);
313    void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
314    void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults&);
315
316    bool handleMouseDoubleClickEvent(const PlatformMouseEvent&);
317
318    bool handleMousePressEvent(const MouseEventWithHitTestResults&);
319    bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&);
320    bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&);
321    bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&);
322#if ENABLE(DRAG_SUPPORT)
323    bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&);
324#endif
325    bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&);
326
327    OptionalCursor selectCursor(const HitTestResult&, bool shiftKey);
328
329    void hoverTimerFired(Timer<EventHandler>&);
330#if ENABLE(CURSOR_SUPPORT)
331    void cursorUpdateTimerFired(Timer<EventHandler>&);
332#endif
333
334    bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
335
336    bool shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, const PlatformWheelEvent&) const;
337
338    bool mouseDownMayStartSelect() const { return m_mouseDownMayStartSelect; }
339
340    static bool isKeyboardOptionTab(KeyboardEvent*);
341    static bool eventInvertsTabsToLinksClientCallResult(KeyboardEvent*);
342
343#if !ENABLE(IOS_TOUCH_EVENTS)
344    void fakeMouseMoveEventTimerFired(Timer<EventHandler>&);
345    void cancelFakeMouseMoveEvent();
346#endif
347
348    bool isInsideScrollbar(const IntPoint&) const;
349
350#if ENABLE(TOUCH_EVENTS)
351    bool dispatchSyntheticTouchEventIfEnabled(const PlatformMouseEvent&);
352#endif
353
354#if !PLATFORM(IOS)
355    void invalidateClick();
356#endif
357
358    Node* nodeUnderMouse() const;
359
360    void updateMouseEventTargetNode(Node*, const PlatformMouseEvent&, bool fireMouseOverOut);
361    void fireMouseOverOut(bool fireMouseOver = true, bool fireMouseOut = true, bool updateLastNodeUnderMouse = true);
362
363    MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&);
364
365    bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
366#if ENABLE(DRAG_SUPPORT)
367    bool dispatchDragEvent(const AtomicString& eventType, Element& target, const PlatformMouseEvent&, DataTransfer*);
368
369    void freeDataTransfer();
370
371    bool handleDrag(const MouseEventWithHitTestResults&, CheckDragHysteresis);
372#endif
373    bool handleMouseUp(const MouseEventWithHitTestResults&);
374#if ENABLE(DRAG_SUPPORT)
375    void clearDragState();
376
377    bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
378
379    bool dragHysteresisExceeded(const FloatPoint&) const;
380    bool dragHysteresisExceeded(const IntPoint&) const;
381#endif // ENABLE(DRAG_SUPPORT)
382
383    bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
384    bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
385    bool passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
386
387    bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
388
389    bool passMousePressEventToScrollbar(MouseEventWithHitTestResults&, Scrollbar*);
390
391    bool passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&);
392    bool passWidgetMouseDownEventToWidget(RenderWidget*);
393
394    bool passMouseDownEventToWidget(Widget*);
395    bool passWheelEventToWidget(const PlatformWheelEvent&, Widget*);
396
397    void defaultSpaceEventHandler(KeyboardEvent*);
398    void defaultBackspaceEventHandler(KeyboardEvent*);
399    void defaultTabEventHandler(KeyboardEvent*);
400    void defaultArrowEventHandler(FocusDirection, KeyboardEvent*);
401
402#if ENABLE(DRAG_SUPPORT)
403    DragSourceAction updateDragSourceActionsAllowed() const;
404#endif
405
406    // The following are called at the beginning of handleMouseUp and handleDrag.
407    // If they return true it indicates that they have consumed the event.
408    bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&);
409#if ENABLE(DRAG_SUPPORT)
410    bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&);
411#endif
412
413#if ENABLE(DRAG_SUPPORT)
414    void updateSelectionForMouseDrag(const HitTestResult&);
415#endif
416
417    void updateLastScrollbarUnderMouse(Scrollbar*, bool);
418
419    void setFrameWasScrolledByUser();
420
421    bool capturesDragging() const { return m_capturesDragging; }
422
423#if PLATFORM(COCOA) && defined(__OBJC__)
424    NSView *mouseDownViewIfStillGood();
425
426    PlatformMouseEvent currentPlatformMouseEvent() const;
427#endif
428
429#if ENABLE(FULLSCREEN_API)
430    bool isKeyEventAllowedInFullScreen(const PlatformKeyboardEvent&) const;
431#endif
432
433    void setLastKnownMousePosition(const PlatformMouseEvent&);
434
435#if ENABLE(CURSOR_VISIBILITY)
436    void startAutoHideCursorTimer();
437    void cancelAutoHideCursorTimer();
438    void autoHideCursorTimerFired(Timer<EventHandler>&);
439#endif
440
441    void clearLatchedState();
442
443    Frame& m_frame;
444
445    bool m_mousePressed;
446    bool m_capturesDragging;
447    RefPtr<Node> m_mousePressNode;
448
449    bool m_mouseDownMayStartSelect;
450#if ENABLE(DRAG_SUPPORT)
451    bool m_mouseDownMayStartDrag;
452    bool m_dragMayStartSelectionInstead;
453#endif
454    bool m_mouseDownWasSingleClickInSelection;
455    enum SelectionInitiationState { HaveNotStartedSelection, PlacedCaret, ExtendedSelection };
456    SelectionInitiationState m_selectionInitiationState;
457
458#if ENABLE(DRAG_SUPPORT)
459    LayoutPoint m_dragStartPos;
460#endif
461
462    bool m_panScrollButtonPressed;
463
464    Timer<EventHandler> m_hoverTimer;
465#if ENABLE(CURSOR_SUPPORT)
466    Timer<EventHandler> m_cursorUpdateTimer;
467#endif
468
469    std::unique_ptr<AutoscrollController> m_autoscrollController;
470    bool m_mouseDownMayStartAutoscroll;
471    bool m_mouseDownWasInSubframe;
472
473#if !ENABLE(IOS_TOUCH_EVENTS)
474    Timer<EventHandler> m_fakeMouseMoveEventTimer;
475#endif
476
477    bool m_svgPan;
478    RefPtr<SVGElementInstance> m_instanceUnderMouse;
479    RefPtr<SVGElementInstance> m_lastInstanceUnderMouse;
480
481    RenderLayer* m_resizeLayer;
482
483    RefPtr<Element> m_capturingMouseEventsElement;
484    bool m_eventHandlerWillResetCapturingMouseEventsElement;
485
486    RefPtr<Element> m_elementUnderMouse;
487    RefPtr<Element> m_lastElementUnderMouse;
488    RefPtr<Frame> m_lastMouseMoveEventSubframe;
489    RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
490    Cursor m_currentMouseCursor;
491
492    int m_clickCount;
493    RefPtr<Node> m_clickNode;
494
495#if ENABLE(IOS_GESTURE_EVENTS)
496    float m_gestureInitialDiameter;
497    float m_gestureLastDiameter;
498    float m_gestureInitialRotation;
499    float m_gestureLastRotation;
500#endif
501
502#if ENABLE(IOS_TOUCH_EVENTS)
503    unsigned m_firstTouchID;
504
505    TouchArray m_touches;
506    EventTargetSet m_gestureTargets;
507    RefPtr<Frame> m_touchEventTargetSubframe;
508#endif
509
510#if ENABLE(DRAG_SUPPORT)
511    RefPtr<Element> m_dragTarget;
512    bool m_shouldOnlyFireDragOverEvent;
513#endif
514
515    RefPtr<HTMLFrameSetElement> m_frameSetBeingResized;
516
517    LayoutSize m_offsetFromResizeCorner; // In the coords of m_resizeLayer.
518
519    bool m_mousePositionIsUnknown;
520    IntPoint m_lastKnownMousePosition;
521    IntPoint m_lastKnownMouseGlobalPosition;
522    IntPoint m_mouseDownPos; // In our view's coords.
523    double m_mouseDownTimestamp;
524    PlatformMouseEvent m_mouseDown;
525
526    std::unique_ptr<WheelEventDeltaTracker> m_recentWheelEventDeltaTracker;
527    RefPtr<Element> m_latchedWheelEventElement;
528    bool m_widgetIsLatched;
529
530    RefPtr<Element> m_previousWheelScrolledElement;
531
532#if PLATFORM(COCOA)
533    NSView *m_mouseDownView;
534    RefPtr<ContainerNode> m_latchedScrollableContainer;
535    bool m_sendingEventToSubview;
536    bool m_startedGestureAtScrollLimit;
537#if !PLATFORM(IOS)
538    int m_activationEventNumber;
539#endif
540#endif
541#if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
542    typedef HashMap<int, RefPtr<EventTarget>> TouchTargetMap;
543    TouchTargetMap m_originatingTouchPointTargets;
544    RefPtr<Document> m_originatingTouchPointDocument;
545    unsigned m_originatingTouchPointTargetKey;
546    bool m_touchPressed;
547#endif
548
549    double m_maxMouseMovedDuration;
550    PlatformEvent::Type m_baseEventType;
551    bool m_didStartDrag;
552    bool m_didLongPressInvokeContextMenu;
553    bool m_isHandlingWheelEvent;
554
555#if ENABLE(CURSOR_VISIBILITY)
556    Timer<EventHandler> m_autoHideCursorTimer;
557#endif
558};
559
560} // namespace WebCore
561
562#endif // EventHandler_h
563