b20c8d76f525e5ad53a62a9ae73e8989d9cf1573
[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::passWheelEventToWidget(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 Widget* widgetForEventTarget(Element* eventTarget)
859 {
860     if (!eventTarget)
861         return nullptr;
862     
863     auto* target = eventTarget->renderer();
864     if (!is<RenderWidget>(target))
865         return nullptr;
866     
867     return downcast<RenderWidget>(*target).widget();
868 }
869
870 static ScrollView* scrollViewForEventTarget(Element* eventTarget)
871 {
872     Widget* widget = widgetForEventTarget(eventTarget);
873     if (!widget)
874         return nullptr;
875     
876     if (!widget->isScrollView())
877         return nullptr;
878     
879     return reinterpret_cast<ScrollView*>(widget);
880 }
881     
882 static bool eventTargetIsPlatformWidget(Element* eventTarget)
883 {
884     Widget* widget = widgetForEventTarget(eventTarget);
885     if (!widget)
886         return false;
887     
888     return widget->platformWidget();
889 }
890
891 static bool latchingIsLockedToPlatformFrame(const Frame& frame)
892 {
893     ScrollLatchingState* latchedState = frame.mainFrame().latchingState();
894     if (!latchedState)
895         return false;
896
897     if (frameHasPlatformWidget(frame) && &frame != latchedState->frame())
898         return true;
899
900     return false;
901 }
902
903 static bool latchingIsLockedToAncestorOfThisFrame(const Frame& frame)
904 {
905     ScrollLatchingState* latchedState = frame.mainFrame().latchingState();
906     if (!latchedState || !latchedState->frame())
907         return false;
908
909     if (&frame == latchedState->frame())
910         return false;
911
912     for (Frame* ancestor = frame.tree().parent(); ancestor; ancestor = ancestor->tree().parent()) {
913         if (ancestor == latchedState->frame())
914             return true;
915     }
916     
917     return false;
918 }
919
920 static ScrollableArea* scrollableAreaForContainerNode(ContainerNode& container)
921 {
922     ScrollableArea* scrollableArea = nullptr;
923
924     if (RenderBox* box = container.renderBox())
925         scrollableArea = scrollableAreaForBox(*box);
926
927     return scrollableArea;
928 }
929
930 static bool latchedToFrameOrBody(ContainerNode& container)
931 {
932     // FIXME(106133): We might need to add or switch to is<HTMLDocumentElement> when this bug is fixed.
933     return is<HTMLFrameSetElement>(container) || is<HTMLBodyElement>(container);
934 }
935
936 void EventHandler::clearOrScheduleClearingLatchedStateIfNeeded(const PlatformWheelEvent& event)
937 {
938     if (!m_frame.isMainFrame())
939         return;
940
941     // Platform does not provide an indication that it will switch from non-momentum to momentum scrolling
942     // when handling wheel events.
943     // Logic below installs a timer when non-momentum scrolling ends. If momentum scroll does not start within that interval,
944     // reset the latched state. If it does, stop the timer, leaving the latched state untouched.
945     if (!m_pendingMomentumWheelEventsTimer.isActive()) {
946         if (event.isEndOfNonMomentumScroll())
947             m_pendingMomentumWheelEventsTimer.startOneShot(resetLatchedStateTimeout);
948     } else {
949         // If another wheel event scrolling starts, stop the timer manually, and reset the latched state immediately.
950         if (event.shouldConsiderLatching()) {
951             m_frame.mainFrame().resetLatchingState();
952             m_pendingMomentumWheelEventsTimer.stop();
953         } else if (event.isTransitioningToMomentumScroll()) {
954             // Wheel events machinary is transitioning to momenthum scrolling, so no need to reset latched state. Stop the timer.
955             m_pendingMomentumWheelEventsTimer.stop();
956         }
957     }
958 }
959
960 void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, RefPtr<Element>& wheelEventTarget, RefPtr<ContainerNode>& scrollableContainer, ScrollableArea*& scrollableArea, bool& isOverWidget)
961 {
962     clearOrScheduleClearingLatchedStateIfNeeded(wheelEvent);
963
964     FrameView* view = m_frame.view();
965
966     scrollableContainer = nullptr;
967     scrollableArea = nullptr;
968     if (!view)
969         scrollableContainer = wheelEventTarget;
970     else {
971         if (eventTargetIsPlatformWidget(wheelEventTarget.get())) {
972             scrollableContainer = wheelEventTarget;
973             scrollableArea = scrollViewForEventTarget(wheelEventTarget.get());
974         } else {
975             scrollableContainer = findEnclosingScrollableContainer(wheelEventTarget.get(), wheelEvent.deltaX(), wheelEvent.deltaY());
976             if (scrollableContainer && !is<HTMLIFrameElement>(wheelEventTarget.get()))
977                 scrollableArea = scrollableAreaForContainerNode(*scrollableContainer);
978             else {
979                 scrollableContainer = view->frame().document()->bodyOrFrameset();
980                 scrollableArea = view;
981             }
982         }
983     }
984     
985     Page* page = m_frame.page();
986     if (scrollableArea && page && page->expectsWheelEventTriggers())
987         scrollableArea->scrollAnimator().setWheelEventTestTrigger(page->testTrigger());
988
989     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
990     if (wheelEvent.shouldConsiderLatching()) {
991         if (scrollableContainer && scrollableArea) {
992             bool startingAtScrollLimit = scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea, wheelEvent.deltaX(), wheelEvent.deltaY());
993             if (!startingAtScrollLimit) {
994                 m_frame.mainFrame().pushNewLatchingState();
995                 latchingState = m_frame.mainFrame().latchingState();
996                 latchingState->setStartedGestureAtScrollLimit(false);
997                 latchingState->setWheelEventElement(wheelEventTarget);
998                 latchingState->setFrame(&m_frame);
999                 // FIXME: What prevents us from deleting this scrollable container while still holding a pointer to it?
1000                 latchingState->setScrollableContainer(scrollableContainer);
1001                 latchingState->setWidgetIsLatched(result.isOverWidget());
1002                 isOverWidget = latchingState->widgetIsLatched();
1003                 m_frame.mainFrame().wheelEventDeltaFilter()->beginFilteringDeltas();
1004             }
1005         }
1006     } else if (wheelEvent.shouldResetLatching())
1007         clearLatchedState();
1008
1009     if (!wheelEvent.shouldResetLatching() && latchingState && latchingState->wheelEventElement()) {
1010         if (latchingIsLockedToPlatformFrame(m_frame))
1011             return;
1012
1013         if (latchingIsLockedToAncestorOfThisFrame(m_frame))
1014             return;
1015
1016         wheelEventTarget = latchingState->wheelEventElement();
1017         isOverWidget = latchingState->widgetIsLatched();
1018         scrollableContainer = latchingState->scrollableContainer();
1019
1020         if (scrollableContainer) {
1021             if (!latchedToFrameOrBody(*scrollableContainer) && !latchingState->widgetIsLatched())
1022                 scrollableArea = scrollableAreaForContainerNode(*scrollableContainer);
1023         }
1024     }
1025 }
1026
1027 void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& wheelEvent)
1028 {
1029     switch (wheelEvent.phase()) {
1030         case PlatformWheelEventPhaseBegan:
1031             m_frame.mainFrame().wheelEventDeltaFilter()->beginFilteringDeltas();
1032             break;
1033         case PlatformWheelEventPhaseEnded:
1034             m_frame.mainFrame().wheelEventDeltaFilter()->endFilteringDeltas();
1035             break;
1036         default:
1037             break;
1038     }
1039     m_frame.mainFrame().wheelEventDeltaFilter()->updateFromDelta(FloatSize(wheelEvent.deltaX(), wheelEvent.deltaY()));
1040 }
1041
1042 static FrameView* frameViewForLatchingState(Frame& frame, ScrollLatchingState* latchingState)
1043 {
1044     if (latchingIsLockedToPlatformFrame(frame))
1045         return frame.view();
1046
1047     return latchingState->frame() ? latchingState->frame()->view() : frame.view();
1048 }
1049
1050 bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEvent, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea)
1051 {
1052     FrameView* view = m_frame.view();
1053     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
1054     if (!view)
1055         return false;
1056
1057     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
1058     if (wheelEvent.useLatchedEventElement() && !latchingIsLockedToAncestorOfThisFrame(m_frame) && latchingState && latchingState->scrollableContainer()) {
1059
1060         m_isHandlingWheelEvent = false;
1061
1062         // WebKit2 code path
1063         if (!frameHasPlatformWidget(m_frame) && !latchingState->startedGestureAtScrollLimit() && scrollableContainer == latchingState->scrollableContainer() && scrollableArea && view != scrollableArea) {
1064             // If we did not start at the scroll limit, do not pass the event on to be handled by enclosing scrollable regions.
1065             return true;
1066         }
1067
1068         if (!latchingState->startedGestureAtScrollLimit())
1069             view = frameViewForLatchingState(m_frame, latchingState);
1070
1071         ASSERT(view);
1072
1073         bool didHandleWheelEvent = view->wheelEvent(wheelEvent);
1074         if (scrollableContainer == latchingState->scrollableContainer()) {
1075             // If we are just starting a scroll event, and have nowhere left to scroll, allow
1076             // the enclosing frame to handle the scroll.
1077             didHandleWheelEvent = !latchingState->startedGestureAtScrollLimit();
1078         }
1079
1080         // If the platform widget is handling the event, we always want to return false.
1081         if (scrollableArea == view && view->platformWidget())
1082             didHandleWheelEvent = false;
1083         
1084         return didHandleWheelEvent;
1085     }
1086     
1087     bool didHandleEvent = view->wheelEvent(wheelEvent);
1088     m_isHandlingWheelEvent = false;
1089     return didHandleEvent;
1090 }
1091
1092 bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent& wheelEvent, const Widget& widget, ContainerNode* scrollableContainer)
1093 {
1094     // WebKit1: Prevent multiple copies of the scrollWheel event from being sent to the NSScrollView widget.
1095     if (frameHasPlatformWidget(m_frame) && widget.isFrameView())
1096         return true;
1097
1098     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
1099     if (!latchingState)
1100         return false;
1101
1102     if (wheelEvent.useLatchedEventElement() && latchingState->scrollableContainer() && scrollableContainer == latchingState->scrollableContainer())
1103         return !latchingState->startedGestureAtScrollLimit();
1104
1105     return false;
1106 }
1107
1108 void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent& wheelEvent, ScrollableArea* scrollableArea)
1109 {
1110     if (!scrollableArea)
1111         return;
1112
1113     // Special case handling for ending wheel gesture to activate snap animation:
1114     if (wheelEvent.phase() != PlatformWheelEventPhaseEnded && wheelEvent.momentumPhase() != PlatformWheelEventPhaseEnded)
1115         return;
1116
1117 #if ENABLE(CSS_SCROLL_SNAP)
1118     if (ScrollAnimator* scrollAnimator = scrollableArea->existingScrollAnimator()) {
1119         scrollAnimator->processWheelEventForScrollSnap(wheelEvent);
1120         if (scrollAnimator->isScrollSnapInProgress())
1121             clearLatchedState();
1122     }
1123 #endif
1124 }
1125
1126 VisibleSelection EventHandler::selectClosestWordFromHitTestResultBasedOnLookup(const HitTestResult& result)
1127 {
1128     if (!m_frame.editor().behavior().shouldSelectBasedOnDictionaryLookup())
1129         return VisibleSelection();
1130
1131     NSDictionary *options = nil;
1132     if (RefPtr<Range> range = DictionaryLookup::rangeAtHitTestResult(result, &options))
1133         return VisibleSelection(*range);
1134
1135     return VisibleSelection();
1136 }
1137
1138 static IntSize autoscrollAdjustmentFactorForScreenBoundaries(const IntPoint& screenPoint, const FloatRect& screenRect)
1139 {
1140     // If the window is at the edge of the screen, and the mouse position is also at that edge of the screen,
1141     // we need to adjust the autoscroll amount in order for the user to be able to autoscroll in that direction.
1142     // We can pretend that the mouse position is slightly beyond the edge of the screen, and then autoscrolling
1143     // will occur as excpected. This function figures out just how much to adjust the autoscroll amount by
1144     // in order to get autoscrolling to feel natural in this situation.
1145
1146     IntSize adjustmentFactor;
1147     
1148 #define EDGE_DISTANCE_THRESHOLD 50
1149 #define PIXELS_MULTIPLIER 20
1150
1151     float screenLeftEdge = screenRect.x();
1152     float insetScreenLeftEdge = screenLeftEdge + EDGE_DISTANCE_THRESHOLD;
1153     float screenRightEdge = screenRect.maxX();
1154     float insetScreenRightEdge = screenRightEdge - EDGE_DISTANCE_THRESHOLD;
1155     if (screenPoint.x() >= screenLeftEdge && screenPoint.x() < insetScreenLeftEdge) {
1156         float distanceFromEdge = screenPoint.x() - screenLeftEdge - EDGE_DISTANCE_THRESHOLD;
1157         if (distanceFromEdge < 0)
1158             adjustmentFactor.setWidth((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
1159     } else if (screenPoint.x() >= insetScreenRightEdge && screenPoint.x() < screenRightEdge) {
1160         float distanceFromEdge = EDGE_DISTANCE_THRESHOLD - (screenRightEdge - screenPoint.x());
1161         if (distanceFromEdge > 0)
1162             adjustmentFactor.setWidth((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
1163     }
1164
1165     float screenTopEdge = screenRect.y();
1166     float insetScreenTopEdge = screenTopEdge + EDGE_DISTANCE_THRESHOLD;
1167     float screenBottomEdge = screenRect.maxY();
1168     float insetScreenBottomEdge = screenBottomEdge - EDGE_DISTANCE_THRESHOLD;
1169
1170     if (screenPoint.y() >= screenTopEdge && screenPoint.y() < insetScreenTopEdge) {
1171         float distanceFromEdge = screenPoint.y() - screenTopEdge - EDGE_DISTANCE_THRESHOLD;
1172         if (distanceFromEdge < 0)
1173             adjustmentFactor.setHeight((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
1174     } else if (screenPoint.y() >= insetScreenBottomEdge && screenPoint.y() < screenBottomEdge) {
1175         float distanceFromEdge = EDGE_DISTANCE_THRESHOLD - (screenBottomEdge - screenPoint.y());
1176         if (distanceFromEdge > 0)
1177             adjustmentFactor.setHeight((distanceFromEdge / EDGE_DISTANCE_THRESHOLD) * PIXELS_MULTIPLIER);
1178     }
1179
1180     return adjustmentFactor;
1181 }
1182
1183 IntPoint EventHandler::effectiveMousePositionForSelectionAutoscroll() const
1184 {
1185     Page* page = m_frame.page();
1186     if (!page)
1187         return m_lastKnownMousePosition;
1188
1189     NSScreen *screen = screenForDisplayID(page->chrome().displayID());
1190     IntSize autoscrollAdjustmentFactor = autoscrollAdjustmentFactorForScreenBoundaries(m_lastKnownMouseGlobalPosition, toUserSpace(screen.frame, nil));
1191
1192     return m_lastKnownMousePosition + autoscrollAdjustmentFactor;
1193 }
1194
1195 }