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