3d7514869621fccf17773afe0271c0e42b0b3894
[WebKit-https.git] / Source / WebCore / page / mac / EventHandlerMac.mm
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 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 #include "config.h"
27 #include "EventHandler.h"
28
29 #include "AXObjectCache.h"
30 #include "BlockExceptions.h"
31 #include "Chrome.h"
32 #include "ChromeClient.h"
33 #include "DataTransfer.h"
34 #include "DragController.h"
35 #include "EventNames.h"
36 #include "FocusController.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "FrameView.h"
40 #include "KeyboardEvent.h"
41 #include "MainFrame.h"
42 #include "MouseEventWithHitTestResults.h"
43 #include "Page.h"
44 #include "Pasteboard.h"
45 #include "PlatformEventFactoryMac.h"
46 #include "RenderLayer.h"
47 #include "RenderListBox.h"
48 #include "RenderWidget.h"
49 #include "RuntimeApplicationChecks.h"
50 #include "ScrollLatchingState.h"
51 #include "ScrollableArea.h"
52 #include "Scrollbar.h"
53 #include "Settings.h"
54 #include "ShadowRoot.h"
55 #include "WebCoreSystemInterface.h"
56 #include <wtf/MainThread.h>
57 #include <wtf/NeverDestroyed.h>
58 #include <wtf/ObjcRuntimeExtras.h>
59
60 namespace WebCore {
61
62 #if ENABLE(DRAG_SUPPORT)
63 const double EventHandler::TextDragDelay = 0.15;
64 #endif
65
66 static RetainPtr<NSEvent>& currentNSEventSlot()
67 {
68     static NeverDestroyed<RetainPtr<NSEvent>> event;
69     return event;
70 }
71
72 NSEvent *EventHandler::currentNSEvent()
73 {
74     return currentNSEventSlot().get();
75 }
76
77 class CurrentEventScope {
78      WTF_MAKE_NONCOPYABLE(CurrentEventScope);
79 public:
80     CurrentEventScope(NSEvent *);
81     ~CurrentEventScope();
82
83 private:
84     RetainPtr<NSEvent> m_savedCurrentEvent;
85 #ifndef NDEBUG
86     RetainPtr<NSEvent> m_event;
87 #endif
88 };
89
90 inline CurrentEventScope::CurrentEventScope(NSEvent *event)
91     : m_savedCurrentEvent(currentNSEventSlot())
92 #ifndef NDEBUG
93     , m_event(event)
94 #endif
95 {
96     currentNSEventSlot() = event;
97 }
98
99 inline CurrentEventScope::~CurrentEventScope()
100 {
101     ASSERT(currentNSEventSlot() == m_event);
102     currentNSEventSlot() = m_savedCurrentEvent;
103 }
104
105 bool EventHandler::wheelEvent(NSEvent *event)
106 {
107     Page* page = m_frame.page();
108     if (!page)
109         return false;
110
111     CurrentEventScope scope(event);
112     return handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event, page->chrome().platformPageClient()));
113 }
114
115 bool EventHandler::keyEvent(NSEvent *event)
116 {
117     BEGIN_BLOCK_OBJC_EXCEPTIONS;
118
119     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
120
121     CurrentEventScope scope(event);
122     return keyEvent(PlatformEventFactory::createPlatformKeyboardEvent(event));
123
124     END_BLOCK_OBJC_EXCEPTIONS;
125
126     return false;
127 }
128
129 void EventHandler::focusDocumentView()
130 {
131     Page* page = m_frame.page();
132     if (!page)
133         return;
134
135     if (FrameView* frameView = m_frame.view()) {
136         if (NSView *documentView = frameView->documentView())
137             page->chrome().focusNSView(documentView);
138     }
139
140     page->focusController().setFocusedFrame(&m_frame);
141 }
142
143 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
144 {
145     // Figure out which view to send the event to.
146     auto target = event.targetNode() ? event.targetNode()->renderer() : nullptr;
147     if (!target || !target->isWidget())
148         return false;
149
150     // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget() will
151     // just pass currentEvent down to the widget, we don't want to call it for events that
152     // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
153     // part of the pressed/released handling.
154     return passMouseDownEventToWidget(toRenderWidget(target)->widget());
155 }
156
157 bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
158 {
159     return passMouseDownEventToWidget(renderWidget->widget());
160 }
161
162 static bool lastEventIsMouseUp()
163 {
164     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
165     // When they finish, currentEvent is the mouseUp that they exited on. We need to update
166     // the WebCore state with this mouseUp, which we never saw. This method lets us detect
167     // that state. Handling this was critical when we used AppKit widgets for form elements.
168     // It's not clear in what cases this is helpful now -- it's possible it can be removed. 
169
170     BEGIN_BLOCK_OBJC_EXCEPTIONS;
171     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
172     return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
173         && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
174         && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
175     END_BLOCK_OBJC_EXCEPTIONS;
176
177     return false;
178 }
179
180 bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
181 {
182     // FIXME: This function always returns true. It should be changed either to return
183     // false in some cases or the return value should be removed.
184
185     RefPtr<Widget> widget = pWidget;
186
187     if (!widget) {
188         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
189         return true;
190     }
191
192     // In WebKit2 we will never have a native widget. Just return early and let the regular event handler machinery take care of
193     // dispatching the event.
194     if (!widget->platformWidget())
195         return false;
196
197     BEGIN_BLOCK_OBJC_EXCEPTIONS;
198
199     NSView *nodeView = widget->platformWidget();
200     ASSERT([nodeView superview]);
201     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
202     if (!view) {
203         // We probably hit the border of a RenderWidget
204         return true;
205     }
206
207     Page* page = m_frame.page();
208     if (!page)
209         return true;
210
211     if (page->chrome().client().firstResponder() != view) {
212         // Normally [NSWindow sendEvent:] handles setting the first responder.
213         // But in our case, the event was sent to the view representing the entire web page.
214         if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
215             page->chrome().client().makeFirstResponder(view);
216     }
217
218     // We need to "defer loading" while tracking the mouse, because tearing down the
219     // page while an AppKit control is tracking the mouse can cause a crash.
220
221     // FIXME: In theory, WebCore now tolerates tear-down while tracking the
222     // mouse. We should confirm that, and then remove the deferrsLoading
223     // hack entirely.
224
225     bool wasDeferringLoading = page->defersLoading();
226     if (!wasDeferringLoading)
227         page->setDefersLoading(true);
228
229     ASSERT(!m_sendingEventToSubview);
230     m_sendingEventToSubview = true;
231
232     {
233         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
234         [view mouseDown:currentNSEvent()];
235     }
236
237     m_sendingEventToSubview = false;
238     
239     if (!wasDeferringLoading)
240         page->setDefersLoading(false);
241
242     // Remember which view we sent the event to, so we can direct the release event properly.
243     m_mouseDownView = view;
244     m_mouseDownWasInSubframe = false;
245
246     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
247     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
248     // the EventHandler state with this mouseUp, which we never saw.
249     // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
250     // is a hole here if the widget consumes both the mouseUp and subsequent events.
251     if (lastEventIsMouseUp())
252         m_mousePressed = false;
253
254     END_BLOCK_OBJC_EXCEPTIONS;
255
256     return true;
257 }
258
259 // Note that this does the same kind of check as [target isDescendantOf:superview].
260 // There are two differences: This is a lot slower because it has to walk the whole
261 // tree, and this works in cases where the target has already been deallocated.
262 static bool findViewInSubviews(NSView *superview, NSView *target)
263 {
264     BEGIN_BLOCK_OBJC_EXCEPTIONS;
265     NSEnumerator *e = [[superview subviews] objectEnumerator];
266     NSView *subview;
267     while ((subview = [e nextObject])) {
268         if (subview == target || findViewInSubviews(subview, target)) {
269             return true;
270         }
271     }
272     END_BLOCK_OBJC_EXCEPTIONS;
273
274     return false;
275 }
276
277 NSView *EventHandler::mouseDownViewIfStillGood()
278 {
279     // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
280     // it could be deallocated already. We search for it in our subview tree; if we don't find
281     // it, we set it to nil.
282     NSView *mouseDownView = m_mouseDownView;
283     if (!mouseDownView) {
284         return nil;
285     }
286     FrameView* topFrameView = m_frame.view();
287     NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
288     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
289         m_mouseDownView = nil;
290         return nil;
291     }
292     return mouseDownView;
293 }
294
295 #if ENABLE(DRAG_SUPPORT)
296 bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
297 {
298     NSView *view = mouseDownViewIfStillGood();
299     
300     if (!view)
301         return false;
302     
303     if (!m_mouseDownWasInSubframe) {
304         ASSERT(!m_sendingEventToSubview);
305         m_sendingEventToSubview = true;
306         BEGIN_BLOCK_OBJC_EXCEPTIONS;
307         [view mouseDragged:currentNSEvent()];
308         END_BLOCK_OBJC_EXCEPTIONS;
309         m_sendingEventToSubview = false;
310     }
311     
312     return true;
313 }
314 #endif // ENABLE(DRAG_SUPPORT)
315
316 bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
317 {
318     NSView *view = mouseDownViewIfStillGood();
319     if (!view)
320         return false;
321
322     if (!m_mouseDownWasInSubframe) {
323         ASSERT(!m_sendingEventToSubview);
324         m_sendingEventToSubview = true;
325         BEGIN_BLOCK_OBJC_EXCEPTIONS;
326         [view mouseUp:currentNSEvent()];
327         END_BLOCK_OBJC_EXCEPTIONS;
328         m_sendingEventToSubview = false;
329     }
330  
331     return true;
332 }
333     
334 bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
335 {
336     BEGIN_BLOCK_OBJC_EXCEPTIONS;
337
338     switch ([currentNSEvent() type]) {
339         case NSLeftMouseDragged:
340         case NSOtherMouseDragged:
341         case NSRightMouseDragged:
342             // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
343             // layout tests.
344             if (!m_mouseDownWasInSubframe)
345                 return false;
346 #if ENABLE(DRAG_SUPPORT)
347             if (subframe->page()->dragController().didInitiateDrag())
348                 return false;
349 #endif
350         case NSMouseMoved:
351             // Since we're passing in currentNSEvent() here, we can call
352             // handleMouseMoveEvent() directly, since the save/restore of
353             // currentNSEvent() that mouseMoved() does would have no effect.
354             ASSERT(!m_sendingEventToSubview);
355             m_sendingEventToSubview = true;
356             subframe->eventHandler().handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
357             m_sendingEventToSubview = false;
358             return true;
359         
360         case NSLeftMouseDown: {
361             Node* node = event.targetNode();
362             if (!node)
363                 return false;
364             auto renderer = node->renderer();
365             if (!renderer || !renderer->isWidget())
366                 return false;
367             Widget* widget = toRenderWidget(renderer)->widget();
368             if (!widget || !widget->isFrameView())
369                 return false;
370             if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
371                 return false;
372             m_mouseDownWasInSubframe = true;
373             return true;
374         }
375         case NSLeftMouseUp: {
376             if (!m_mouseDownWasInSubframe)
377                 return false;
378             ASSERT(!m_sendingEventToSubview);
379             m_sendingEventToSubview = true;
380             subframe->eventHandler().handleMouseReleaseEvent(currentPlatformMouseEvent());
381             m_sendingEventToSubview = false;
382             return true;
383         }
384         default:
385             return false;
386     }
387     END_BLOCK_OBJC_EXCEPTIONS;
388
389     return false;
390 }
391
392 static IMP originalNSScrollViewScrollWheel;
393 static bool _nsScrollViewScrollWheelShouldRetainSelf;
394 static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
395
396 static bool nsScrollViewScrollWheelShouldRetainSelf()
397 {
398     ASSERT(isMainThread());
399
400     return _nsScrollViewScrollWheelShouldRetainSelf;
401 }
402
403 static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
404 {
405     ASSERT(isMainThread());
406
407     if (!originalNSScrollViewScrollWheel) {
408         Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
409         originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
410     }
411
412     _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
413 }
414
415 static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
416 {
417     bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
418
419     if (shouldRetainSelf)
420         [self retain];
421     wtfCallIMP<void>(originalNSScrollViewScrollWheel, self, selector, event);
422     if (shouldRetainSelf)
423         [self release];
424 }
425
426 bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget& widget)
427 {
428     BEGIN_BLOCK_OBJC_EXCEPTIONS;
429
430     NSView* nodeView = widget.platformWidget();
431     if (!nodeView) {
432         // WebKit2 code path.
433         if (!is<FrameView>(widget))
434             return false;
435
436         return downcast<FrameView>(widget).frame().eventHandler().handleWheelEvent(wheelEvent);
437     }
438
439     if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview) 
440         return false;
441
442     ASSERT(nodeView);
443     ASSERT([nodeView superview]);
444     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
445     if (!view) {
446         // We probably hit the border of a RenderWidget
447         return false;
448     }
449
450     ASSERT(!m_sendingEventToSubview);
451     m_sendingEventToSubview = true;
452     // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
453     // crash if the NSScrollView is released during timer or network callback dispatch
454     // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
455     setNSScrollViewScrollWheelShouldRetainSelf(true);
456     [view scrollWheel:currentNSEvent()];
457     setNSScrollViewScrollWheelShouldRetainSelf(false);
458     m_sendingEventToSubview = false;
459     return true;
460
461     END_BLOCK_OBJC_EXCEPTIONS;
462     return false;
463 }
464
465 void EventHandler::mouseDown(NSEvent *event)
466 {
467     FrameView* v = m_frame.view();
468     if (!v || m_sendingEventToSubview)
469         return;
470
471     BEGIN_BLOCK_OBJC_EXCEPTIONS;
472     
473     m_mouseDownView = nil;
474     
475     CurrentEventScope scope(event);
476
477     handleMousePressEvent(currentPlatformMouseEvent());
478
479     END_BLOCK_OBJC_EXCEPTIONS;
480 }
481
482 void EventHandler::mouseDragged(NSEvent *event)
483 {
484     FrameView* v = m_frame.view();
485     if (!v || m_sendingEventToSubview)
486         return;
487
488     BEGIN_BLOCK_OBJC_EXCEPTIONS;
489
490     CurrentEventScope scope(event);
491     handleMouseMoveEvent(currentPlatformMouseEvent());
492
493     END_BLOCK_OBJC_EXCEPTIONS;
494 }
495
496 void EventHandler::mouseUp(NSEvent *event)
497 {
498     FrameView* v = m_frame.view();
499     if (!v || m_sendingEventToSubview)
500         return;
501
502     BEGIN_BLOCK_OBJC_EXCEPTIONS;
503
504     CurrentEventScope scope(event);
505
506     // Our behavior here is a little different that Qt. Qt always sends
507     // a mouse release event, even for a double click. To correct problems
508     // in khtml's DOM click event handling we do not send a release here
509     // for a double click. Instead we send that event from FrameView's
510     // handleMouseDoubleClickEvent. Note also that the third click of
511     // a triple click is treated as a single click, but the fourth is then
512     // treated as another double click. Hence the "% 2" below.
513     int clickCount = [event clickCount];
514     if (clickCount > 0 && clickCount % 2 == 0)
515         handleMouseDoubleClickEvent(currentPlatformMouseEvent());
516     else
517         handleMouseReleaseEvent(currentPlatformMouseEvent());
518     
519     m_mouseDownView = nil;
520
521     END_BLOCK_OBJC_EXCEPTIONS;
522 }
523
524 /*
525  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
526  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
527  is done, this routine is used to fix things up.  When a mouse down started us tracking in
528  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
529  key down started us tracking in the widget, we post a fake key up to balance things out.
530  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
531  be over after the tracking is done.
532  */
533 void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
534 {
535     FrameView* view = m_frame.view();
536     if (!view)
537         return;
538
539     BEGIN_BLOCK_OBJC_EXCEPTIONS;
540
541     m_sendingEventToSubview = false;
542     int eventType = [initiatingEvent type];
543     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
544         NSEvent *fakeEvent = nil;
545         if (eventType == NSLeftMouseDown) {
546             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
547                                            location:[initiatingEvent locationInWindow]
548                                       modifierFlags:[initiatingEvent modifierFlags]
549                                           timestamp:[initiatingEvent timestamp]
550                                        windowNumber:[initiatingEvent windowNumber]
551                                             context:[initiatingEvent context]
552                                         eventNumber:[initiatingEvent eventNumber]
553                                          clickCount:[initiatingEvent clickCount]
554                                            pressure:[initiatingEvent pressure]];
555         
556             [NSApp postEvent:fakeEvent atStart:YES];
557         } else { // eventType == NSKeyDown
558             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
559                                          location:[initiatingEvent locationInWindow]
560                                     modifierFlags:[initiatingEvent modifierFlags]
561                                         timestamp:[initiatingEvent timestamp]
562                                      windowNumber:[initiatingEvent windowNumber]
563                                           context:[initiatingEvent context]
564                                        characters:[initiatingEvent characters] 
565                       charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
566                                         isARepeat:[initiatingEvent isARepeat] 
567                                           keyCode:[initiatingEvent keyCode]];
568             [NSApp postEvent:fakeEvent atStart:YES];
569         }
570         // FIXME: We should really get the current modifierFlags here, but there's no way to poll
571         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
572         // no up-to-date cache of them anywhere.
573 #pragma clang diagnostic push
574 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
575         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
576                                        location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
577                                   modifierFlags:[initiatingEvent modifierFlags]
578                                       timestamp:[initiatingEvent timestamp]
579                                    windowNumber:[initiatingEvent windowNumber]
580                                         context:[initiatingEvent context]
581                                     eventNumber:0
582                                      clickCount:0
583                                        pressure:0];
584 #pragma clang diagnostic pop
585         [NSApp postEvent:fakeEvent atStart:YES];
586     }
587     
588     END_BLOCK_OBJC_EXCEPTIONS;
589 }
590
591 void EventHandler::mouseMoved(NSEvent *event)
592 {
593     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
594     // These happen because WebKit sometimes has to fake up moved events.
595     if (!m_frame.view() || m_mousePressed || m_sendingEventToSubview)
596         return;
597
598     BEGIN_BLOCK_OBJC_EXCEPTIONS;
599     CurrentEventScope scope(event);
600     mouseMoved(currentPlatformMouseEvent());
601     END_BLOCK_OBJC_EXCEPTIONS;
602 }
603
604 void EventHandler::passMouseMovedEventToScrollbars(NSEvent *event)
605 {
606     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
607     // These happen because WebKit sometimes has to fake up moved events.
608     if (!m_frame.view() || m_mousePressed || m_sendingEventToSubview)
609         return;
610
611     BEGIN_BLOCK_OBJC_EXCEPTIONS;
612     CurrentEventScope scope(event);
613     passMouseMovedEventToScrollbars(currentPlatformMouseEvent());
614     END_BLOCK_OBJC_EXCEPTIONS;
615 }
616
617 static bool frameHasPlatformWidget(const Frame& frame)
618 {
619     if (FrameView* frameView = frame.view()) {
620         if (frameView->platformWidget())
621             return true;
622     }
623
624     return false;
625 }
626
627 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
628 {
629     // WebKit1 code path.
630     if (frameHasPlatformWidget(m_frame))
631         return passSubframeEventToSubframe(mev, subframe);
632
633     // WebKit2 code path.
634     subframe->eventHandler().handleMousePressEvent(mev.event());
635     return true;
636 }
637
638 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
639 {
640     // WebKit1 code path.
641     if (frameHasPlatformWidget(m_frame))
642         return passSubframeEventToSubframe(mev, subframe, hoveredNode);
643
644 #if ENABLE(DRAG_SUPPORT)
645     // WebKit2 code path.
646     if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
647         return false;
648 #endif
649
650     subframe->eventHandler().handleMouseMoveEvent(mev.event(), hoveredNode);
651     return true;
652 }
653
654 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
655 {
656     // WebKit1 code path.
657     if (frameHasPlatformWidget(m_frame))
658         return passSubframeEventToSubframe(mev, subframe);
659
660     // WebKit2 code path.
661     subframe->eventHandler().handleMouseReleaseEvent(mev.event());
662     return true;
663 }
664
665 PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
666 {
667     NSView *windowView = nil;
668     if (Page* page = m_frame.page())
669         windowView = page->chrome().platformPageClient();
670     return PlatformEventFactory::createPlatformMouseEvent(currentNSEvent(), windowView);
671 }
672
673 bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
674 {
675     return m_activationEventNumber == event.eventNumber();
676 }
677
678 #if ENABLE(DRAG_SUPPORT)
679
680 PassRefPtr<DataTransfer> EventHandler::createDraggingDataTransfer() const
681 {
682     // Must be done before ondragstart adds types and data to the pboard,
683     // also done for security, as it erases data from the last drag.
684     OwnPtr<Pasteboard> pasteboard = Pasteboard::create(NSDragPboard);
685     pasteboard->clear();
686     return DataTransfer::createForDragAndDrop();
687 }
688
689 #endif
690
691 bool EventHandler::tabsToAllFormControls(KeyboardEvent* event) const
692 {
693     Page* page = m_frame.page();
694     if (!page)
695         return false;
696
697     KeyboardUIMode keyboardUIMode = page->chrome().client().keyboardUIMode();
698     bool handlingOptionTab = isKeyboardOptionTab(event);
699
700     // If tab-to-links is off, option-tab always highlights all controls
701     if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
702         return true;
703     
704     // If system preferences say to include all controls, we always include all controls
705     if (keyboardUIMode & KeyboardAccessFull)
706         return true;
707     
708     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
709     if (keyboardUIMode & KeyboardAccessTabsToLinks)
710         return !handlingOptionTab;
711     
712     return handlingOptionTab;
713 }
714
715 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
716 {
717 #if ENABLE(DASHBOARD_SUPPORT)
718     if (m_frame.settings().usesDashboardBackwardCompatibilityMode())
719         return true;
720 #endif
721         
722     if (m_frame.settings().needsKeyboardEventDisambiguationQuirks())
723         return true;
724
725     return false;
726 }
727
728 unsigned EventHandler::accessKeyModifiers()
729 {
730     // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
731     // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
732     // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
733     if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
734         return PlatformEvent::CtrlKey;
735
736     return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
737 }
738
739 static ContainerNode* findEnclosingScrollableContainer(ContainerNode& node)
740 {
741     // Find the first node with a valid scrollable area starting with the current
742     // node and traversing its parents (or shadow hosts).
743     for (ContainerNode* candidate = &node; candidate; candidate = candidate->parentOrShadowHostNode()) {
744         RenderBox* box = candidate->renderBox();
745         if (box && box->canBeScrolledAndHasScrollableArea())
746             return candidate;
747     }
748     
749     return nullptr;
750 }
751
752 static bool deltaIsPredominantlyVertical(float deltaX, float deltaY)
753 {
754     return std::abs(deltaY) > std::abs(deltaX);
755 }
756     
757 static bool scrolledToEdgeInDominantDirection(const ContainerNode& container, const ScrollableArea& area, float deltaX, float deltaY)
758 {
759     if (!container.renderer())
760         return true;
761
762     const RenderStyle& style = container.renderer()->style();
763
764     if (!deltaIsPredominantlyVertical(deltaX, deltaY) && deltaX) {
765         if (style.overflowX() == OHIDDEN)
766             return true;
767
768         if (deltaX < 0)
769             return area.scrolledToRight();
770         
771         return area.scrolledToLeft();
772     }
773
774     if (style.overflowY() == OHIDDEN)
775         return true;
776
777     if (deltaY < 0)
778         return area.scrolledToBottom();
779     
780     return area.scrolledToTop();
781 }
782
783 static Widget* widgetForEventTarget(Element* eventTarget)
784 {
785     if (!eventTarget)
786         return nullptr;
787     
788     RenderElement* target = eventTarget->renderer();
789     if (!target || !target->isWidget())
790         return nullptr;
791     
792     return toRenderWidget(target)->widget();
793 }
794
795 static ScrollView* scrollViewForEventTarget(Element* eventTarget)
796 {
797     Widget* widget = widgetForEventTarget(eventTarget);
798     if (!widget)
799         return nullptr;
800     
801     if (!widget->isScrollView())
802         return nullptr;
803     
804     return reinterpret_cast<ScrollView*>(widget);
805 }
806     
807 static bool eventTargetIsPlatformWidget(Element* eventTarget)
808 {
809     Widget* widget = widgetForEventTarget(eventTarget);
810     if (!widget)
811         return false;
812     
813     return widget->platformWidget();
814 }
815
816 static bool latchingIsLockedToPlatformFrame(const Frame& frame)
817 {
818     ScrollLatchingState* latchedState = frame.mainFrame().latchingState();
819     if (!latchedState)
820         return false;
821
822     if (frameHasPlatformWidget(frame) && &frame != latchedState->frame())
823         return true;
824
825     return false;
826 }
827     
828 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, RefPtr<Element>& wheelEventTarget, RefPtr<ContainerNode>& scrollableContainer, ScrollableArea*& scrollableArea, bool& isOverWidget)
829 {
830     FrameView* view = m_frame.view();
831
832     scrollableContainer = nullptr;
833     scrollableArea = nullptr;
834     if (!view || !view->frame().isMainFrame()) {
835         scrollableContainer = wheelEventTarget;
836         scrollableArea = view;
837     } else {
838         if (eventTargetIsPlatformWidget(wheelEventTarget.get())) {
839             scrollableContainer = wheelEventTarget;
840             scrollableArea = scrollViewForEventTarget(wheelEventTarget.get());
841         } else {
842             scrollableContainer = findEnclosingScrollableContainer(*wheelEventTarget);
843             if (scrollableContainer) {
844                 if (RenderBox* box = scrollableContainer->renderBox()) {
845                     if (box->isListBox())
846                         scrollableArea = toRenderListBox(box);
847                     else
848                         scrollableArea = box->layer();
849                 }
850             }
851         }
852     }
853     
854     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
855     ASSERT(latchingState);
856     if (wheelEvent.shouldConsiderLatching()) {
857         if (scrollableArea && scrollableContainer)
858             latchingState->setStartedGestureAtScrollLimit(scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea, wheelEvent.deltaX(), wheelEvent.deltaY()));
859         else
860             latchingState->setStartedGestureAtScrollLimit(false);
861         latchingState->setWheelEventElement(wheelEventTarget);
862         latchingState->setFrame(&m_frame);
863         // FIXME: What prevents us from deleting this scrollable container while still holding a pointer to it?
864         latchingState->setScrollableContainer(scrollableContainer);
865         latchingState->setWidgetIsLatched(result.isOverWidget());
866         isOverWidget = latchingState->widgetIsLatched();
867         m_frame.mainFrame().wheelEventDeltaTracker()->beginTrackingDeltas();
868     } else if (wheelEvent.shouldResetLatching())
869         clearLatchedState();
870
871     if (!wheelEvent.shouldResetLatching() && latchingState->wheelEventElement()) {
872         if (latchingIsLockedToPlatformFrame(m_frame))
873             return;
874
875         wheelEventTarget = latchingState->wheelEventElement();
876         isOverWidget = latchingState->widgetIsLatched();
877     }
878 }
879
880 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& wheelEvent)
881 {
882     switch (wheelEvent.phase()) {
883         case PlatformWheelEventPhaseBegan:
884             m_frame.mainFrame().wheelEventDeltaTracker()->beginTrackingDeltas();
885             break;
886         case PlatformWheelEventPhaseEnded:
887             m_frame.mainFrame().wheelEventDeltaTracker()->endTrackingDeltas();
888             break;
889         default:
890             break;
891     }
892
893     m_frame.mainFrame().wheelEventDeltaTracker()->recordWheelEventDelta(wheelEvent);
894 }
895
896 static FrameView* frameViewForLatchingState(Frame& frame, ScrollLatchingState* latchingState)
897 {
898     if (latchingIsLockedToPlatformFrame(frame))
899         return frame.view();
900
901     return latchingState->frame() ? latchingState->frame()->view() : frame.view();
902 }
903
904 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEvent, Element* wheelEventTarget, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea)
905 {
906     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
907     FrameView* view = m_frame.view();
908
909     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
910     ASSERT(latchingState);
911     if (wheelEvent.useLatchedEventElement() && latchingState->scrollableContainer()) {
912         view = frameViewForLatchingState(m_frame, latchingState);
913         if (!view || !view->frame().isMainFrame()) {
914             bool didHandleWheelEvent = view && view->wheelEvent(wheelEvent);
915             if (!didHandleWheelEvent && scrollableContainer == latchingState->scrollableContainer()) {
916                 // If we are just starting a scroll event, and have nowhere left to scroll, allow
917                 // the enclosing frame to handle the scroll.
918                 didHandleWheelEvent = !latchingState->startedGestureAtScrollLimit();
919                 if (!didHandleWheelEvent)
920                     latchingState->setFrame(nullptr);
921             }
922
923             // If the platform widget is handling the event, we always want to return false
924             if (view && scrollableArea == view && view->platformWidget())
925                 didHandleWheelEvent = false;
926             
927             m_isHandlingWheelEvent = false;
928             return didHandleWheelEvent;
929         }
930         
931         if (scrollableArea && !latchingState->startedGestureAtScrollLimit() && scrollableContainer == latchingState->scrollableContainer()) {
932             m_isHandlingWheelEvent = false;
933
934             if (eventTargetIsPlatformWidget(wheelEventTarget))
935                 return !latchingState->startedGestureAtScrollLimit();
936
937             return true;
938         }
939     }
940     
941     bool didHandleEvent = view ? view->wheelEvent(wheelEvent) : false;
942     m_isHandlingWheelEvent = false;
943     return didHandleEvent;
944 }
945
946 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent& wheelEvent, const Widget& widget, ContainerNode* scrollableContainer)
947 {
948     // WebKit1: Prevent multiple copies of the scrollWheel event from being sent to the NSScrollView widget.
949     if (frameHasPlatformWidget(m_frame) && widget.isFrameView())
950         return true;
951
952     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
953     ASSERT(latchingState);
954     if (wheelEvent.useLatchedEventElement() && latchingState->scrollableContainer() && scrollableContainer == latchingState->scrollableContainer())
955         return !latchingState->startedGestureAtScrollLimit();
956
957     return false;
958 }
959     
960 }