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