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