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