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