1/*
2 * Copyright (C) 2006, 2007, 2009, 2010, 2011 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 COMPUTER, 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 COMPUTER, 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 "DragActions.h"
30#include "FocusDirection.h"
31#include "HitTestRequest.h"
32#include "PlatformMouseEvent.h"
33#include "ScrollTypes.h"
34#include "TextEventInputType.h"
35#include "Timer.h"
36#include <wtf/Forward.h>
37#include <wtf/OwnPtr.h>
38#include <wtf/RefPtr.h>
39
40#if PLATFORM(MAC) && !defined(__OBJC__)
41class NSView;
42#endif
43
44#if ENABLE(TOUCH_EVENTS)
45#include <wtf/HashMap.h>
46#endif
47
48namespace WebCore {
49
50class Clipboard;
51class Cursor;
52class Event;
53class EventTarget;
54class FloatPoint;
55class FloatQuad;
56class Frame;
57class HTMLFrameSetElement;
58class HitTestRequest;
59class HitTestResult;
60class KeyboardEvent;
61class MouseEventWithHitTestResults;
62class Node;
63class PlatformKeyboardEvent;
64class PlatformTouchEvent;
65class PlatformWheelEvent;
66class RenderLayer;
67class RenderObject;
68class RenderWidget;
69class SVGElementInstance;
70class Scrollbar;
71class TextEvent;
72class TouchEvent;
73class WheelEvent;
74class Widget;
75
76#if ENABLE(GESTURE_EVENTS)
77class PlatformGestureEvent;
78#endif
79
80#if ENABLE(GESTURE_RECOGNIZER)
81class PlatformGestureRecognizer;
82#endif
83
84#if ENABLE(DRAG_SUPPORT)
85extern const int LinkDragHysteresis;
86extern const int ImageDragHysteresis;
87extern const int TextDragHysteresis;
88extern const int GeneralDragHysteresis;
89#endif // ENABLE(DRAG_SUPPORT)
90
91enum HitTestScrollbars { ShouldHitTestScrollbars, DontHitTestScrollbars };
92
93class EventHandler {
94    WTF_MAKE_NONCOPYABLE(EventHandler);
95public:
96    EventHandler(Frame*);
97    ~EventHandler();
98
99    void clear();
100
101#if ENABLE(DRAG_SUPPORT)
102    void updateSelectionForMouseDrag();
103#endif
104
105    Node* mousePressNode() const;
106    void setMousePressNode(PassRefPtr<Node>);
107
108    void startPanScrolling(RenderObject*);
109    bool panScrollInProgress() { return m_panScrollInProgress; }
110    void setPanScrollInProgress(bool inProgress) { m_panScrollInProgress = inProgress; }
111
112    void stopAutoscrollTimer(bool rendererIsBeingDestroyed = false);
113    RenderObject* autoscrollRenderer() const;
114    void updateAutoscrollRenderer();
115
116    void dispatchFakeMouseMoveEventSoon();
117    void dispatchFakeMouseMoveEventSoonInQuad(const FloatQuad&);
118
119    HitTestResult hitTestResultAtPoint(const IntPoint&, bool allowShadowContent, bool ignoreClipping = false,
120                                       HitTestScrollbars scrollbars = DontHitTestScrollbars,
121                                       HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active,
122                                       const IntSize& padding = IntSize());
123
124    bool mousePressed() const { return m_mousePressed; }
125    void setMousePressed(bool pressed) { m_mousePressed = pressed; }
126
127    void setCapturingMouseEventsNode(PassRefPtr<Node>); // A caller is responsible for resetting capturing node to 0.
128
129#if ENABLE(DRAG_SUPPORT)
130    bool updateDragAndDrop(const PlatformMouseEvent&, Clipboard*);
131    void cancelDragAndDrop(const PlatformMouseEvent&, Clipboard*);
132    bool performDragAndDrop(const PlatformMouseEvent&, Clipboard*);
133#endif
134
135    void scheduleHoverStateUpdate();
136
137    void setResizingFrameSet(HTMLFrameSetElement*);
138
139    void resizeLayerDestroyed();
140
141    IntPoint currentMousePosition() const;
142
143    void setIgnoreWheelEvents(bool);
144
145    static Frame* subframeForTargetNode(Node*);
146    static Frame* subframeForHitTestResult(const MouseEventWithHitTestResults&);
147
148    bool scrollOverflow(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
149    bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
150
151    bool scrollRecursively(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
152    bool logicalScrollRecursively(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
153
154#if ENABLE(DRAG_SUPPORT)
155    bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto
156#endif
157
158    bool shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&) const;
159
160    bool tabsToLinks(KeyboardEvent*) const;
161    bool tabsToAllFormControls(KeyboardEvent*) const;
162
163    bool mouseDownMayStartSelect() const { return m_mouseDownMayStartSelect; }
164
165    bool mouseMoved(const PlatformMouseEvent&);
166
167    void lostMouseCapture();
168
169    bool handleMousePressEvent(const PlatformMouseEvent&);
170    bool handleMouseMoveEvent(const PlatformMouseEvent&, HitTestResult* hoveredNode = 0);
171    bool handleMouseReleaseEvent(const PlatformMouseEvent&);
172    bool handleWheelEvent(PlatformWheelEvent&);
173    void defaultWheelEventHandler(Node*, WheelEvent*);
174
175#if ENABLE(GESTURE_EVENTS)
176    bool handleGestureEvent(const PlatformGestureEvent&);
177#endif
178
179#if ENABLE(CONTEXT_MENUS)
180    bool sendContextMenuEvent(const PlatformMouseEvent&);
181    bool sendContextMenuEventForKey();
182#endif
183
184    void setMouseDownMayStartAutoscroll() { m_mouseDownMayStartAutoscroll = true; }
185
186    bool needsKeyboardEventDisambiguationQuirks() const;
187
188    static unsigned accessKeyModifiers();
189    bool handleAccessKey(const PlatformKeyboardEvent&);
190    bool keyEvent(const PlatformKeyboardEvent&);
191    void defaultKeyboardEventHandler(KeyboardEvent*);
192
193    bool handleTextInputEvent(const String& text, Event* underlyingEvent = 0, TextEventInputType = TextEventInputKeyboard);
194    void defaultTextInputEventHandler(TextEvent*);
195
196#if ENABLE(DRAG_SUPPORT)
197    bool eventMayStartDrag(const PlatformMouseEvent&) const;
198
199    void dragSourceEndedAt(const PlatformMouseEvent&, DragOperation);
200#endif
201
202    void focusDocumentView();
203
204    void capsLockStateMayHaveChanged();
205
206    void sendResizeEvent();
207    void sendScrollEvent();
208
209#if PLATFORM(MAC) && defined(__OBJC__)
210    PassRefPtr<KeyboardEvent> currentKeyboardEvent() const;
211
212    void mouseDown(NSEvent *);
213    void mouseDragged(NSEvent *);
214    void mouseUp(NSEvent *);
215    void mouseMoved(NSEvent *);
216    bool keyEvent(NSEvent *);
217    bool wheelEvent(NSEvent *);
218
219#if ENABLE(CONTEXT_MENUS)
220    bool sendContextMenuEvent(NSEvent *);
221#endif
222    bool eventMayStartDrag(NSEvent *);
223
224    void sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent);
225
226    void setActivationEventNumber(int num) { m_activationEventNumber = num; }
227
228    static NSEvent *currentNSEvent();
229#endif
230
231#if ENABLE(TOUCH_EVENTS)
232    bool handleTouchEvent(const PlatformTouchEvent&);
233#if PLATFORM(ANDROID)
234    void setCapturingTouchEventsNode(PassRefPtr<Node>);
235#endif
236#endif
237
238    static bool isKeyboardOptionTab(KeyboardEvent*);
239
240private:
241#if ENABLE(DRAG_SUPPORT)
242    enum DragAndDropHandleType {
243        UpdateDragAndDrop,
244        CancelDragAndDrop,
245        PerformDragAndDrop
246    };
247
248    struct EventHandlerDragState {
249        WTF_MAKE_NONCOPYABLE(EventHandlerDragState); WTF_MAKE_FAST_ALLOCATED;
250    public:
251        EventHandlerDragState() { }
252        RefPtr<Node> m_dragSrc; // element that may be a drag source, for the current mouse gesture
253        bool m_dragSrcIsLink;
254        bool m_dragSrcIsImage;
255        bool m_dragSrcInSelection;
256        bool m_dragSrcMayBeDHTML;
257        bool m_dragSrcMayBeUA; // Are DHTML and/or the UserAgent allowed to drag out?
258        bool m_dragSrcIsDHTML;
259        RefPtr<Clipboard> m_dragClipboard; // used on only the source side of dragging
260    };
261    static EventHandlerDragState& dragState();
262    static const double TextDragDelay;
263
264    bool canHandleDragAndDropForTarget(DragAndDropHandleType, Node* target, const PlatformMouseEvent&, Clipboard*, bool* accepted = 0);
265
266    PassRefPtr<Clipboard> createDraggingClipboard() const;
267#endif // ENABLE(DRAG_SUPPORT)
268
269    bool eventActivatedView(const PlatformMouseEvent&) const;
270    void selectClosestWordFromMouseEvent(const MouseEventWithHitTestResults&);
271    void selectClosestWordOrLinkFromMouseEvent(const MouseEventWithHitTestResults&);
272
273    bool handleMouseDoubleClickEvent(const PlatformMouseEvent&);
274
275    static Node* targetNode(const MouseEventWithHitTestResults&);
276    static Node* targetNode(const HitTestResult&);
277
278    bool handleMousePressEvent(const MouseEventWithHitTestResults&);
279    bool handleMousePressEventSingleClick(const MouseEventWithHitTestResults&);
280    bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&);
281    bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&);
282#if ENABLE(DRAG_SUPPORT)
283    bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&);
284#endif
285    bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&);
286
287    void handleKeyboardSelectionMovement(KeyboardEvent*);
288
289    Cursor selectCursor(const MouseEventWithHitTestResults&, Scrollbar*);
290#if ENABLE(PAN_SCROLLING)
291    void updatePanScrollState();
292#endif
293
294    void hoverTimerFired(Timer<EventHandler>*);
295
296    static bool canMouseDownStartSelect(Node*);
297#if ENABLE(DRAG_SUPPORT)
298    static bool canMouseDragExtendSelect(Node*);
299#endif
300
301    void handleAutoscroll(RenderObject*);
302    void startAutoscrollTimer();
303    void setAutoscrollRenderer(RenderObject*);
304    void autoscrollTimerFired(Timer<EventHandler>*);
305
306    void fakeMouseMoveEventTimerFired(Timer<EventHandler>*);
307    void cancelFakeMouseMoveEvent();
308
309    void invalidateClick();
310
311    Node* nodeUnderMouse() const;
312
313    void updateMouseEventTargetNode(Node*, const PlatformMouseEvent&, bool fireMouseOverOut);
314    void fireMouseOverOut(bool fireMouseOver = true, bool fireMouseOut = true, bool updateLastNodeUnderMouse = true);
315
316    MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const PlatformMouseEvent&);
317
318    bool dispatchMouseEvent(const AtomicString& eventType, Node* target, bool cancelable, int clickCount, const PlatformMouseEvent&, bool setUnder);
319#if ENABLE(DRAG_SUPPORT)
320    bool dispatchDragEvent(const AtomicString& eventType, Node* target, const PlatformMouseEvent&, Clipboard*);
321
322    void freeClipboard();
323
324    bool handleDrag(const MouseEventWithHitTestResults&);
325#endif
326    bool handleMouseUp(const MouseEventWithHitTestResults&);
327#if ENABLE(DRAG_SUPPORT)
328    void clearDragState();
329
330    bool dispatchDragSrcEvent(const AtomicString& eventType, const PlatformMouseEvent&);
331
332    bool dragHysteresisExceeded(const FloatPoint&) const;
333    bool dragHysteresisExceeded(const IntPoint&) const;
334#endif // ENABLE(DRAG_SUPPORT)
335
336    bool passMousePressEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
337    bool passMouseMoveEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
338    bool passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe);
339
340    bool passSubframeEventToSubframe(MouseEventWithHitTestResults&, Frame* subframe, HitTestResult* hoveredNode = 0);
341
342    bool passMousePressEventToScrollbar(MouseEventWithHitTestResults&, Scrollbar*);
343
344    bool passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&);
345    bool passWidgetMouseDownEventToWidget(RenderWidget*);
346
347    bool passMouseDownEventToWidget(Widget*);
348    bool passWheelEventToWidget(PlatformWheelEvent&, Widget*);
349
350    void defaultSpaceEventHandler(KeyboardEvent*);
351    void defaultBackspaceEventHandler(KeyboardEvent*);
352    void defaultTabEventHandler(KeyboardEvent*);
353    void defaultArrowEventHandler(FocusDirection, KeyboardEvent*);
354
355#if ENABLE(DRAG_SUPPORT)
356    void allowDHTMLDrag(bool& flagDHTML, bool& flagUA) const;
357#endif
358
359    // The following are called at the beginning of handleMouseUp and handleDrag.
360    // If they return true it indicates that they have consumed the event.
361    bool eventLoopHandleMouseUp(const MouseEventWithHitTestResults&);
362#if ENABLE(DRAG_SUPPORT)
363    bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&);
364#endif
365
366#if ENABLE(DRAG_SUPPORT)
367    void updateSelectionForMouseDrag(const HitTestResult&);
368#endif
369
370    void updateLastScrollbarUnderMouse(Scrollbar*, bool);
371
372    void setFrameWasScrolledByUser();
373
374    FocusDirection focusDirectionForKey(const AtomicString&) const;
375
376    bool capturesDragging() const { return m_capturesDragging; }
377
378#if PLATFORM(MAC) && defined(__OBJC__)
379    NSView *mouseDownViewIfStillGood();
380
381    PlatformMouseEvent currentPlatformMouseEvent() const;
382#endif
383
384    Frame* m_frame;
385
386    bool m_mousePressed;
387    bool m_capturesDragging;
388    RefPtr<Node> m_mousePressNode;
389
390    bool m_mouseDownMayStartSelect;
391#if ENABLE(DRAG_SUPPORT)
392    bool m_mouseDownMayStartDrag;
393#endif
394    bool m_mouseDownWasSingleClickInSelection;
395    bool m_beganSelectingText;
396
397#if ENABLE(DRAG_SUPPORT)
398    IntPoint m_dragStartPos;
399#endif
400
401    IntPoint m_panScrollStartPos;
402    bool m_panScrollInProgress;
403
404    bool m_panScrollButtonPressed;
405    bool m_springLoadedPanScrollInProgress;
406
407    Timer<EventHandler> m_hoverTimer;
408
409    Timer<EventHandler> m_autoscrollTimer;
410    RenderObject* m_autoscrollRenderer;
411    bool m_autoscrollInProgress;
412    bool m_mouseDownMayStartAutoscroll;
413    bool m_mouseDownWasInSubframe;
414
415    Timer<EventHandler> m_fakeMouseMoveEventTimer;
416
417#if ENABLE(SVG)
418    bool m_svgPan;
419    RefPtr<SVGElementInstance> m_instanceUnderMouse;
420    RefPtr<SVGElementInstance> m_lastInstanceUnderMouse;
421#endif
422
423    RenderLayer* m_resizeLayer;
424
425    RefPtr<Node> m_capturingMouseEventsNode;
426    bool m_eventHandlerWillResetCapturingMouseEventsNode;
427
428    RefPtr<Node> m_nodeUnderMouse;
429    RefPtr<Node> m_lastNodeUnderMouse;
430    RefPtr<Frame> m_lastMouseMoveEventSubframe;
431    RefPtr<Scrollbar> m_lastScrollbarUnderMouse;
432
433    int m_clickCount;
434    RefPtr<Node> m_clickNode;
435
436#if ENABLE(DRAG_SUPPORT)
437    RefPtr<Node> m_dragTarget;
438    bool m_shouldOnlyFireDragOverEvent;
439#endif
440
441    RefPtr<HTMLFrameSetElement> m_frameSetBeingResized;
442
443    IntSize m_offsetFromResizeCorner;   // in the coords of m_resizeLayer
444
445    IntPoint m_currentMousePosition;
446    IntPoint m_mouseDownPos; // in our view's coords
447    double m_mouseDownTimestamp;
448    PlatformMouseEvent m_mouseDown;
449
450    bool m_useLatchedWheelEventNode;
451    RefPtr<Node> m_latchedWheelEventNode;
452    bool m_widgetIsLatched;
453
454    RefPtr<Node> m_previousWheelScrolledNode;
455
456#if PLATFORM(MAC)
457    NSView *m_mouseDownView;
458    bool m_sendingEventToSubview;
459    int m_activationEventNumber;
460#endif
461#if ENABLE(TOUCH_EVENTS)
462    typedef HashMap<int, RefPtr<EventTarget> > TouchTargetMap;
463    TouchTargetMap m_originatingTouchPointTargets;
464    bool m_touchPressed;
465#if PLATFORM(ANDROID)
466    RefPtr<Node> m_capturingTouchEventsNode;
467#endif
468#endif
469#if ENABLE(GESTURE_RECOGNIZER)
470    OwnPtr<PlatformGestureRecognizer> m_gestureRecognizer;
471#endif
472};
473
474} // namespace WebCore
475
476#endif // EventHandler_h
477