Reviewed by Darin.
[WebKit-https.git] / WebCore / page / mac / EventHandlerMac.mm
1 /*
2  * Copyright (C) 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 "BlockExceptions.h"
30 #include "ClipboardMac.h"
31 #include "Cursor.h"
32 #include "Document.h"
33 #include "DragController.h"
34 #include "EventNames.h"
35 #include "FloatPoint.h"
36 #include "FocusController.h"
37 #include "FoundationExtras.h"
38 #include "FrameLoader.h"
39 #include "Frame.h"
40 #include "FrameTree.h"
41 #include "FrameView.h"
42 #include "HTMLFrameOwnerElement.h"
43 #include "HTMLFrameSetElement.h"
44 #include "HitTestRequest.h"
45 #include "HitTestResult.h"
46 #include "KeyboardEvent.h"
47 #include "MouseEventWithHitTestResults.h"
48 #include "Page.h"
49 #include "PlatformKeyboardEvent.h"
50 #include "PlatformScrollBar.h"
51 #include "PlatformWheelEvent.h"
52 #include "RenderWidget.h"
53 #include "Settings.h"
54 #include "WebCoreFrameBridge.h"
55
56 namespace WebCore {
57
58 using namespace EventNames;
59
60 static RetainPtr<NSEvent>& currentEvent()
61 {
62     static RetainPtr<NSEvent> event;
63     return event;
64 }
65
66 NSEvent *EventHandler::currentNSEvent()
67 {
68     return currentEvent().get();
69 }
70
71 bool EventHandler::wheelEvent(NSEvent *event)
72 {
73     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
74     currentEvent() = event;
75
76     PlatformWheelEvent wheelEvent(event);
77     handleWheelEvent(wheelEvent);
78
79     ASSERT(currentEvent() == event);
80     currentEvent() = oldCurrentEvent;
81
82     return wheelEvent.isAccepted();
83 }
84
85 PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
86 {
87     NSEvent *event = [NSApp currentEvent];
88     if (!event)
89         return 0;
90     switch ([event type]) {
91         case NSKeyDown: {
92             PlatformKeyboardEvent platformEvent(event);
93             platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
94             return new KeyboardEvent(platformEvent, m_frame->document() ? m_frame->document()->defaultView() : 0);
95         }
96         case NSKeyUp:
97             return new KeyboardEvent(event, m_frame->document() ? m_frame->document()->defaultView() : 0);
98         default:
99             return 0;
100     }
101 }
102
103 static inline bool isKeyboardOptionTab(KeyboardEvent* event)
104 {
105     return event
106     && (event->type() == keydownEvent || event->type() == keypressEvent)
107     && event->altKey()
108     && event->keyIdentifier() == "U+0009";    
109 }
110
111 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
112 {
113     return isKeyboardOptionTab(event);
114 }
115
116 bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
117 {
118     KeyboardUIMode keyboardUIMode = [m_frame->bridge() keyboardUIMode];
119     bool handlingOptionTab = isKeyboardOptionTab(event);
120
121     // If tab-to-links is off, option-tab always highlights all controls
122     if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
123         return true;
124     
125     // If system preferences say to include all controls, we always include all controls
126     if (keyboardUIMode & KeyboardAccessFull)
127         return true;
128     
129     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
130     if (keyboardUIMode & KeyboardAccessTabsToLinks)
131         return !handlingOptionTab;
132     
133     return handlingOptionTab;
134 }
135
136 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
137 {
138     static BOOL checkedSafari = NO;
139     static BOOL isSafari = NO;
140
141     if (!checkedSafari) {
142         isSafari = [[[NSBundle mainBundle] bundleIdentifier] isEqualToString:@"com.apple.Safari"];
143         checkedSafari = YES;
144     }
145     
146     Document* document = m_frame->document();
147     if (!document)
148         return false;
149
150     // RSS view needs arrow key keypress events.
151     if (isSafari && document->url().startsWith("feed:", false) || document->url().startsWith("feeds:", false))
152         return true;
153     Settings* settings = m_frame->settings();
154     if (!settings)
155         return false;
156     return settings->usesDashboardBackwardCompatibilityMode() || settings->needsKeyboardEventDisambiguationQuirks();
157 }
158
159 bool EventHandler::keyEvent(NSEvent *event)
160 {
161     bool result;
162     BEGIN_BLOCK_OBJC_EXCEPTIONS;
163
164     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
165
166     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
167     currentEvent() = event;
168
169     result = keyEvent(PlatformKeyboardEvent(event));
170     
171     ASSERT(currentEvent() == event);
172     currentEvent() = oldCurrentEvent;
173
174     return result;
175
176     END_BLOCK_OBJC_EXCEPTIONS;
177
178     return false;
179 }
180
181 void EventHandler::focusDocumentView()
182 {
183     Page* page = m_frame->page();
184     if (!page)
185         return;
186
187     if (FrameView* frameView = m_frame->view())
188         if (NSView *documentView = frameView->getDocumentView())
189             page->chrome()->focusNSView(documentView);
190     
191     page->focusController()->setFocusedFrame(m_frame);
192 }
193
194 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
195 {
196     // Figure out which view to send the event to.
197     RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
198     if (!target || !target->isWidget())
199         return false;
200     
201     // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
202     // just pass currentEvent down to the widget, we don't want to call it for events that
203     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
204     // part of the pressed/released handling.
205     return passMouseDownEventToWidget(static_cast<RenderWidget*>(target)->widget());
206 }
207
208 bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
209 {
210     return passMouseDownEventToWidget(renderWidget->widget());
211 }
212
213 static bool lastEventIsMouseUp()
214 {
215     // Many AK widgets run their own event loops and consume events while the mouse is down.
216     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
217     // the khtml state with this mouseUp, which khtml never saw.  This method lets us detect
218     // that state.
219
220     BEGIN_BLOCK_OBJC_EXCEPTIONS;
221     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
222     if (currentEvent() != currentEventAfterHandlingMouseDown &&
223         [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp &&
224         [currentEventAfterHandlingMouseDown timestamp] >= [currentEvent().get() timestamp])
225             return true;
226     END_BLOCK_OBJC_EXCEPTIONS;
227
228     return false;
229 }
230
231 bool EventHandler::passMouseDownEventToWidget(Widget* widget)
232 {
233     // FIXME: this method always returns true
234
235     if (!widget) {
236         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
237         return true;
238     }
239
240     BEGIN_BLOCK_OBJC_EXCEPTIONS;
241     
242     NSView *nodeView = widget->getView();
243     ASSERT(nodeView);
244     ASSERT([nodeView superview]);
245     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]];
246     if (!view)
247         // We probably hit the border of a RenderWidget
248         return true;
249     
250     if ([m_frame->bridge() firstResponder] == view) {
251         // In the case where we just became first responder, we should send the mouseDown:
252         // to the NSTextField, not the NSTextField's editor. This code makes sure that happens.
253         // If we don't do this, we see a flash of selected text when clicking in a text field.
254         // FIXME: This is the only caller of textViewWasFirstResponderAtMouseDownTime. When we
255         // eliminate all use of NSTextField/NSTextView in form fields we can eliminate this code,
256         // and textViewWasFirstResponderAtMouseDownTime:, and the instance variable WebHTMLView
257         // keeps solely to support textViewWasFirstResponderAtMouseDownTime:.
258         if ([view isKindOfClass:[NSTextView class]] && ![m_frame->bridge() textViewWasFirstResponderAtMouseDownTime:(NSTextView *)view]) {
259             NSView *superview = view;
260             while (superview != nodeView) {
261                 superview = [superview superview];
262                 ASSERT(superview);
263                 if ([superview isKindOfClass:[NSControl class]]) {
264                     NSControl *control = static_cast<NSControl*>(superview);
265                     if ([control currentEditor] == view)
266                         view = superview;
267                     break;
268                 }
269             }
270         }
271     } else {
272         // Normally [NSWindow sendEvent:] handles setting the first responder.
273         // But in our case, the event was sent to the view representing the entire web page.
274         if ([currentEvent().get() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey]) {
275             [m_frame->bridge() makeFirstResponder:view];
276         }
277     }
278
279     // We need to "defer loading" while tracking the mouse, because tearing down the
280     // page while an AppKit control is tracking the mouse can cause a crash.
281     
282     // FIXME: In theory, WebCore now tolerates tear-down while tracking the
283     // mouse. We should confirm that, and then remove the deferrsLoading
284     // hack entirely.
285     
286     bool wasDeferringLoading = m_frame->page()->defersLoading();
287     if (!wasDeferringLoading)
288         m_frame->page()->setDefersLoading(true);
289
290     ASSERT(!m_sendingEventToSubview);
291     m_sendingEventToSubview = true;
292     [view mouseDown:currentEvent().get()];
293     m_sendingEventToSubview = false;
294     
295     if (!wasDeferringLoading)
296         m_frame->page()->setDefersLoading(false);
297
298     // Remember which view we sent the event to, so we can direct the release event properly.
299     m_mouseDownView = view;
300     m_mouseDownWasInSubframe = false;
301     
302     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
303     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
304     // the EventHandler state with this mouseUp, which we never saw.
305     // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
306     // is a hole here if the widget consumes both the mouseUp and subsequent events.
307     if (lastEventIsMouseUp())
308         m_mousePressed = false;
309
310     END_BLOCK_OBJC_EXCEPTIONS;
311
312     return true;
313 }
314     
315 // Note that this does the same kind of check as [target isDescendantOf:superview].
316 // There are two differences: This is a lot slower because it has to walk the whole
317 // tree, and this works in cases where the target has already been deallocated.
318 static bool findViewInSubviews(NSView *superview, NSView *target)
319 {
320     BEGIN_BLOCK_OBJC_EXCEPTIONS;
321     NSEnumerator *e = [[superview subviews] objectEnumerator];
322     NSView *subview;
323     while ((subview = [e nextObject])) {
324         if (subview == target || findViewInSubviews(subview, target)) {
325             return true;
326         }
327     }
328     END_BLOCK_OBJC_EXCEPTIONS;
329     
330     return false;
331 }
332
333 NSView *EventHandler::mouseDownViewIfStillGood()
334 {
335     // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
336     // it could be deallocated already. We search for it in our subview tree; if we don't find
337     // it, we set it to nil.
338     NSView *mouseDownView = m_mouseDownView;
339     if (!mouseDownView) {
340         return nil;
341     }
342     FrameView* topFrameView = m_frame->view();
343     NSView *topView = topFrameView ? topFrameView->getView() : nil;
344     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
345         m_mouseDownView = nil;
346         return nil;
347     }
348     return mouseDownView;
349 }
350
351 bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
352 {
353     return m_activationEventNumber == event.eventNumber();
354 }
355
356 bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
357 {
358     NSView *view = mouseDownViewIfStillGood();
359     
360     if (!view)
361         return false;
362     
363     if (!m_mouseDownWasInSubframe) {
364         m_sendingEventToSubview = true;
365         BEGIN_BLOCK_OBJC_EXCEPTIONS;
366         [view mouseDragged:currentEvent().get()];
367         END_BLOCK_OBJC_EXCEPTIONS;
368         m_sendingEventToSubview = false;
369     }
370     
371     return true;
372 }
373     
374 Clipboard* EventHandler::createDraggingClipboard() const 
375 {
376     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
377     // Must be done before ondragstart adds types and data to the pboard,
378     // also done for security, as it erases data from the last drag
379     [pasteboard declareTypes:[NSArray array] owner:nil];
380     return new ClipboardMac(true, pasteboard, ClipboardWritable, m_frame);
381 }
382     
383 bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
384 {
385     NSView *view = mouseDownViewIfStillGood();
386     if (!view)
387         return false;
388     
389     if (!m_mouseDownWasInSubframe) {
390         m_sendingEventToSubview = true;
391         BEGIN_BLOCK_OBJC_EXCEPTIONS;
392         [view mouseUp:currentEvent().get()];
393         END_BLOCK_OBJC_EXCEPTIONS;
394         m_sendingEventToSubview = false;
395     }
396  
397     return true;
398 }
399     
400 bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
401 {
402     BEGIN_BLOCK_OBJC_EXCEPTIONS;
403
404     switch ([currentEvent().get() type]) {
405         case NSMouseMoved:
406             // Since we're passing in currentEvent() here, we can call
407             // handleMouseMoveEvent() directly, since the save/restore of
408             // currentEvent() that mouseMoved() does would have no effect.
409             subframe->eventHandler()->handleMouseMoveEvent(currentEvent().get(), hoveredNode);
410             return true;
411         
412         case NSLeftMouseDown: {
413             Node* node = event.targetNode();
414             if (!node)
415                 return false;
416             RenderObject* renderer = node->renderer();
417             if (!renderer || !renderer->isWidget())
418                 return false;
419             Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
420             if (!widget || !widget->isFrameView())
421                 return false;
422             if (!passWidgetMouseDownEventToWidget(static_cast<RenderWidget*>(renderer)))
423                 return false;
424             m_mouseDownWasInSubframe = true;
425             return true;
426         }
427         case NSLeftMouseUp: {
428             if (!m_mouseDownWasInSubframe)
429                 return false;
430             NSView *view = mouseDownViewIfStillGood();
431             if (!view)
432                 return false;
433             ASSERT(!m_sendingEventToSubview);
434             m_sendingEventToSubview = true;
435             [view mouseUp:currentEvent().get()];
436             m_sendingEventToSubview = false;
437             return true;
438         }
439         case NSLeftMouseDragged: {
440             if (!m_mouseDownWasInSubframe)
441                 return false;
442             NSView *view = mouseDownViewIfStillGood();
443             if (!view)
444                 return false;
445             ASSERT(!m_sendingEventToSubview);
446             m_sendingEventToSubview = true;
447             [view mouseDragged:currentEvent().get()];
448             m_sendingEventToSubview = false;
449             return true;
450         }
451         default:
452             return false;
453     }
454     END_BLOCK_OBJC_EXCEPTIONS;
455
456     return false;
457 }
458
459 bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget)
460 {
461     BEGIN_BLOCK_OBJC_EXCEPTIONS;
462         
463     if ([currentEvent().get() type] != NSScrollWheel || m_sendingEventToSubview || !widget) 
464         return false;
465
466     NSView *nodeView = widget->getView();
467     ASSERT(nodeView);
468     ASSERT([nodeView superview]);
469     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentEvent().get() locationInWindow] fromView:nil]];
470     if (!view)
471         // We probably hit the border of a RenderWidget
472         return false;
473
474     m_sendingEventToSubview = true;
475     [view scrollWheel:currentEvent().get()];
476     m_sendingEventToSubview = false;
477     return true;
478             
479     END_BLOCK_OBJC_EXCEPTIONS;
480     return false;
481 }
482
483 void EventHandler::mouseDown(NSEvent *event)
484 {
485     FrameView* v = m_frame->view();
486     if (!v || m_sendingEventToSubview)
487         return;
488
489     BEGIN_BLOCK_OBJC_EXCEPTIONS;
490     
491     m_frame->loader()->resetMultipleFormSubmissionProtection();
492
493     m_mouseDownView = nil;
494     dragState().m_dragSrc = 0;
495     
496     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
497     currentEvent() = event;
498     m_mouseDown = PlatformMouseEvent(event);
499     
500     handleMousePressEvent(event);
501     
502     ASSERT(currentEvent() == event);
503     currentEvent() = oldCurrentEvent;
504
505     END_BLOCK_OBJC_EXCEPTIONS;
506 }
507
508 void EventHandler::mouseDragged(NSEvent *event)
509 {
510     FrameView* v = m_frame->view();
511     if (!v || m_sendingEventToSubview)
512         return;
513
514     BEGIN_BLOCK_OBJC_EXCEPTIONS;
515
516     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
517     currentEvent() = event;
518
519     handleMouseMoveEvent(event);
520     
521     ASSERT(currentEvent() == event);
522     currentEvent() = oldCurrentEvent;
523
524     END_BLOCK_OBJC_EXCEPTIONS;
525 }
526
527 void EventHandler::mouseUp(NSEvent *event)
528 {
529     FrameView* v = m_frame->view();
530     if (!v || m_sendingEventToSubview)
531         return;
532
533     BEGIN_BLOCK_OBJC_EXCEPTIONS;
534
535     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
536     currentEvent() = event;
537
538     // Our behavior here is a little different that Qt. Qt always sends
539     // a mouse release event, even for a double click. To correct problems
540     // in khtml's DOM click event handling we do not send a release here
541     // for a double click. Instead we send that event from FrameView's
542     // handleMouseDoubleClickEvent. Note also that the third click of
543     // a triple click is treated as a single click, but the fourth is then
544     // treated as another double click. Hence the "% 2" below.
545     int clickCount = [event clickCount];
546     if (clickCount > 0 && clickCount % 2 == 0)
547         handleMouseDoubleClickEvent(event);
548     else
549         handleMouseReleaseEvent(event);
550     
551     ASSERT(currentEvent() == event);
552     currentEvent() = oldCurrentEvent;
553     
554     m_mouseDownView = nil;
555
556     END_BLOCK_OBJC_EXCEPTIONS;
557 }
558
559 /*
560  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
561  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
562  is done, this routine is used to fix things up.  When a mouse down started us tracking in
563  the widget, we post a fake mouse up to balance the mouse down we started with. When a 
564  key down started us tracking in the widget, we post a fake key up to balance things out.
565  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to 
566  be over after the tracking is done.
567  */
568 void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
569 {
570     BEGIN_BLOCK_OBJC_EXCEPTIONS;
571
572     m_sendingEventToSubview = false;
573     int eventType = [initiatingEvent type];
574     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
575         NSEvent *fakeEvent = nil;
576         if (eventType == NSLeftMouseDown) {
577             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
578                                     location:[initiatingEvent locationInWindow]
579                                 modifierFlags:[initiatingEvent modifierFlags]
580                                     timestamp:[initiatingEvent timestamp]
581                                 windowNumber:[initiatingEvent windowNumber]
582                                         context:[initiatingEvent context]
583                                     eventNumber:[initiatingEvent eventNumber]
584                                     clickCount:[initiatingEvent clickCount]
585                                     pressure:[initiatingEvent pressure]];
586         
587             [NSApp postEvent:fakeEvent atStart:YES];
588         } else { // eventType == NSKeyDown
589             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
590                                     location:[initiatingEvent locationInWindow]
591                                modifierFlags:[initiatingEvent modifierFlags]
592                                    timestamp:[initiatingEvent timestamp]
593                                 windowNumber:[initiatingEvent windowNumber]
594                                      context:[initiatingEvent context]
595                                   characters:[initiatingEvent characters] 
596                  charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers] 
597                                    isARepeat:[initiatingEvent isARepeat] 
598                                      keyCode:[initiatingEvent keyCode]];
599             [NSApp postEvent:fakeEvent atStart:YES];
600         }
601         // FIXME:  We should really get the current modifierFlags here, but there's no way to poll
602         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
603         // no up-to-date cache of them anywhere.
604         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
605                                        location:[[m_frame->bridge() window] convertScreenToBase:[NSEvent mouseLocation]]
606                                   modifierFlags:[initiatingEvent modifierFlags]
607                                       timestamp:[initiatingEvent timestamp]
608                                    windowNumber:[initiatingEvent windowNumber]
609                                         context:[initiatingEvent context]
610                                     eventNumber:0
611                                      clickCount:0
612                                        pressure:0];
613         [NSApp postEvent:fakeEvent atStart:YES];
614     }
615     
616     END_BLOCK_OBJC_EXCEPTIONS;
617 }
618
619 void EventHandler::mouseMoved(NSEvent *event)
620 {
621     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
622     // These happen because WebKit sometimes has to fake up moved events.
623     if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
624         return;
625     
626     BEGIN_BLOCK_OBJC_EXCEPTIONS;
627
628     RetainPtr<NSEvent> oldCurrentEvent = currentEvent();
629     currentEvent() = event;
630     
631     mouseMoved(PlatformMouseEvent(event));
632     
633     ASSERT(currentEvent() == event);
634     currentEvent() = oldCurrentEvent;
635
636     END_BLOCK_OBJC_EXCEPTIONS;
637 }
638
639 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
640 {
641     return passSubframeEventToSubframe(mev, subframe);
642 }
643
644 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
645 {
646     return passSubframeEventToSubframe(mev, subframe, hoveredNode);
647 }
648
649 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
650 {
651     return passSubframeEventToSubframe(mev, subframe);
652 }
653
654 bool EventHandler::passMousePressEventToScrollbar(MouseEventWithHitTestResults&, PlatformScrollbar* scrollbar)
655 {
656     return passMouseDownEventToWidget(scrollbar);
657 }
658
659 }