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