Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009 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 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 "AXObjectCache.h"
     30 #include "BlockExceptions.h"
     31 #include "Chrome.h"
     32 #include "ChromeClient.h"
     33 #include "ClipboardMac.h"
     34 #include "DragController.h"
     35 #include "EventNames.h"
     36 #include "FocusController.h"
     37 #include "Frame.h"
     38 #include "FrameLoader.h"
     39 #include "FrameView.h"
     40 #include "KeyboardEvent.h"
     41 #include "MouseEventWithHitTestResults.h"
     42 #include "NotImplemented.h"
     43 #include "Page.h"
     44 #include "PlatformKeyboardEvent.h"
     45 #include "PlatformWheelEvent.h"
     46 #include "RenderWidget.h"
     47 #include "RuntimeApplicationChecks.h"
     48 #include "Scrollbar.h"
     49 #include "Settings.h"
     50 #include "WebCoreSystemInterface.h"
     51 #include <objc/objc-runtime.h>
     52 #include <wtf/StdLibExtras.h>
     53 
     54 #if !(defined(OBJC_API_VERSION) && OBJC_API_VERSION > 0)
     55 static inline IMP method_setImplementation(Method m, IMP i)
     56 {
     57     IMP oi = m->method_imp;
     58     m->method_imp = i;
     59     return oi;
     60 }
     61 #endif
     62 
     63 namespace WebCore {
     64 
     65 #if ENABLE(DRAG_SUPPORT)
     66 const double EventHandler::TextDragDelay = 0.15;
     67 #endif
     68 
     69 #if !ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE)
     70 
     71 static RetainPtr<NSEvent>& currentNSEventSlot()
     72 {
     73     DEFINE_STATIC_LOCAL(RetainPtr<NSEvent>, event, ());
     74     return event;
     75 }
     76 
     77 NSEvent *EventHandler::currentNSEvent()
     78 {
     79     return currentNSEventSlot().get();
     80 }
     81 
     82 class CurrentEventScope : public Noncopyable {
     83 public:
     84     CurrentEventScope(NSEvent *);
     85     ~CurrentEventScope();
     86 
     87 private:
     88     RetainPtr<NSEvent> m_savedCurrentEvent;
     89 #ifndef NDEBUG
     90     RetainPtr<NSEvent> m_event;
     91 #endif
     92 };
     93 
     94 inline CurrentEventScope::CurrentEventScope(NSEvent *event)
     95     : m_savedCurrentEvent(currentNSEventSlot())
     96 #ifndef NDEBUG
     97     , m_event(event)
     98 #endif
     99 {
    100     currentNSEventSlot() = event;
    101 }
    102 
    103 inline CurrentEventScope::~CurrentEventScope()
    104 {
    105     ASSERT(currentNSEventSlot() == m_event);
    106     currentNSEventSlot() = m_savedCurrentEvent;
    107 }
    108 
    109 bool EventHandler::wheelEvent(NSEvent *event)
    110 {
    111     Page* page = m_frame->page();
    112     if (!page)
    113         return false;
    114 
    115     CurrentEventScope scope(event);
    116 
    117     m_useLatchedWheelEventNode = wkIsLatchingWheelEvent(event);
    118 
    119     PlatformWheelEvent wheelEvent(event, page->chrome()->platformPageClient());
    120     handleWheelEvent(wheelEvent);
    121 
    122     return wheelEvent.isAccepted();
    123 }
    124 
    125 PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
    126 {
    127     NSEvent *event = [NSApp currentEvent];
    128     if (!event)
    129         return 0;
    130     switch ([event type]) {
    131         case NSKeyDown: {
    132             PlatformKeyboardEvent platformEvent(event);
    133             platformEvent.disambiguateKeyDownEvent(PlatformKeyboardEvent::RawKeyDown);
    134             return KeyboardEvent::create(platformEvent, m_frame->document()->defaultView());
    135         }
    136         case NSKeyUp:
    137             return KeyboardEvent::create(event, m_frame->document()->defaultView());
    138         default:
    139             return 0;
    140     }
    141 }
    142 
    143 bool EventHandler::keyEvent(NSEvent *event)
    144 {
    145     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    146 
    147     ASSERT([event type] == NSKeyDown || [event type] == NSKeyUp);
    148 
    149     CurrentEventScope scope(event);
    150     return keyEvent(PlatformKeyboardEvent(event));
    151 
    152     END_BLOCK_OBJC_EXCEPTIONS;
    153 
    154     return false;
    155 }
    156 
    157 void EventHandler::focusDocumentView()
    158 {
    159     Page* page = m_frame->page();
    160     if (!page)
    161         return;
    162 
    163     if (FrameView* frameView = m_frame->view()) {
    164         if (NSView *documentView = frameView->documentView())
    165             page->chrome()->focusNSView(documentView);
    166     }
    167 
    168     page->focusController()->setFocusedFrame(m_frame);
    169 }
    170 
    171 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
    172 {
    173     // Figure out which view to send the event to.
    174     RenderObject* target = event.targetNode() ? event.targetNode()->renderer() : 0;
    175     if (!target || !target->isWidget())
    176         return false;
    177 
    178     // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget will
    179     // just pass currentEvent down to the widget, we don't want to call it for events that
    180     // don't correspond to Cocoa events.  The mousedown/ups will have already been passed on as
    181     // part of the pressed/released handling.
    182     return passMouseDownEventToWidget(toRenderWidget(target)->widget());
    183 }
    184 
    185 bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
    186 {
    187     return passMouseDownEventToWidget(renderWidget->widget());
    188 }
    189 
    190 static bool lastEventIsMouseUp()
    191 {
    192     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
    193     // When they finish, currentEvent is the mouseUp that they exited on. We need to update
    194     // the WebCore state with this mouseUp, which we never saw. This method lets us detect
    195     // that state. Handling this was critical when we used AppKit widgets for form elements.
    196     // It's not clear in what cases this is helpful now -- it's possible it can be removed.
    197 
    198     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    199     NSEvent *currentEventAfterHandlingMouseDown = [NSApp currentEvent];
    200     return EventHandler::currentNSEvent() != currentEventAfterHandlingMouseDown
    201         && [currentEventAfterHandlingMouseDown type] == NSLeftMouseUp
    202         && [currentEventAfterHandlingMouseDown timestamp] >= [EventHandler::currentNSEvent() timestamp];
    203     END_BLOCK_OBJC_EXCEPTIONS;
    204 
    205     return false;
    206 }
    207 
    208 bool EventHandler::passMouseDownEventToWidget(Widget* pWidget)
    209 {
    210     // FIXME: This function always returns true. It should be changed either to return
    211     // false in some cases or the return value should be removed.
    212 
    213     RefPtr<Widget> widget = pWidget;
    214 
    215     if (!widget) {
    216         LOG_ERROR("hit a RenderWidget without a corresponding Widget, means a frame is half-constructed");
    217         return true;
    218     }
    219 
    220     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    221 
    222     NSView *nodeView = widget->platformWidget();
    223     ASSERT(nodeView);
    224     ASSERT([nodeView superview]);
    225     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
    226     if (!view) {
    227         // We probably hit the border of a RenderWidget
    228         return true;
    229     }
    230 
    231     Page* page = m_frame->page();
    232     if (!page)
    233         return true;
    234 
    235     if (page->chrome()->client()->firstResponder() != view) {
    236         // Normally [NSWindow sendEvent:] handles setting the first responder.
    237         // But in our case, the event was sent to the view representing the entire web page.
    238         if ([currentNSEvent() clickCount] <= 1 && [view acceptsFirstResponder] && [view needsPanelToBecomeKey])
    239             page->chrome()->client()->makeFirstResponder(view);
    240     }
    241 
    242     // We need to "defer loading" while tracking the mouse, because tearing down the
    243     // page while an AppKit control is tracking the mouse can cause a crash.
    244 
    245     // FIXME: In theory, WebCore now tolerates tear-down while tracking the
    246     // mouse. We should confirm that, and then remove the deferrsLoading
    247     // hack entirely.
    248 
    249     bool wasDeferringLoading = page->defersLoading();
    250     if (!wasDeferringLoading)
    251         page->setDefersLoading(true);
    252 
    253     ASSERT(!m_sendingEventToSubview);
    254     m_sendingEventToSubview = true;
    255     NSView *outerView = widget->getOuterView();
    256     widget->beforeMouseDown(outerView, widget.get());
    257     [view mouseDown:currentNSEvent()];
    258     widget->afterMouseDown(outerView, widget.get());
    259     m_sendingEventToSubview = false;
    260 
    261     if (!wasDeferringLoading)
    262         page->setDefersLoading(false);
    263 
    264     // Remember which view we sent the event to, so we can direct the release event properly.
    265     m_mouseDownView = view;
    266     m_mouseDownWasInSubframe = false;
    267 
    268     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
    269     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
    270     // the EventHandler state with this mouseUp, which we never saw.
    271     // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
    272     // is a hole here if the widget consumes both the mouseUp and subsequent events.
    273     if (lastEventIsMouseUp())
    274         m_mousePressed = false;
    275 
    276     END_BLOCK_OBJC_EXCEPTIONS;
    277 
    278     return true;
    279 }
    280 
    281 // Note that this does the same kind of check as [target isDescendantOf:superview].
    282 // There are two differences: This is a lot slower because it has to walk the whole
    283 // tree, and this works in cases where the target has already been deallocated.
    284 static bool findViewInSubviews(NSView *superview, NSView *target)
    285 {
    286     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    287     NSEnumerator *e = [[superview subviews] objectEnumerator];
    288     NSView *subview;
    289     while ((subview = [e nextObject])) {
    290         if (subview == target || findViewInSubviews(subview, target)) {
    291             return true;
    292         }
    293     }
    294     END_BLOCK_OBJC_EXCEPTIONS;
    295 
    296     return false;
    297 }
    298 
    299 NSView *EventHandler::mouseDownViewIfStillGood()
    300 {
    301     // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
    302     // it could be deallocated already. We search for it in our subview tree; if we don't find
    303     // it, we set it to nil.
    304     NSView *mouseDownView = m_mouseDownView;
    305     if (!mouseDownView) {
    306         return nil;
    307     }
    308     FrameView* topFrameView = m_frame->view();
    309     NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
    310     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
    311         m_mouseDownView = nil;
    312         return nil;
    313     }
    314     return mouseDownView;
    315 }
    316 
    317 #if ENABLE(DRAG_SUPPORT)
    318 bool EventHandler::eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&)
    319 {
    320     NSView *view = mouseDownViewIfStillGood();
    321 
    322     if (!view)
    323         return false;
    324 
    325     if (!m_mouseDownWasInSubframe) {
    326         ASSERT(!m_sendingEventToSubview);
    327         m_sendingEventToSubview = true;
    328         BEGIN_BLOCK_OBJC_EXCEPTIONS;
    329         [view mouseDragged:currentNSEvent()];
    330         END_BLOCK_OBJC_EXCEPTIONS;
    331         m_sendingEventToSubview = false;
    332     }
    333 
    334     return true;
    335 }
    336 #endif // ENABLE(DRAG_SUPPORT)
    337 
    338 bool EventHandler::eventLoopHandleMouseUp(const MouseEventWithHitTestResults&)
    339 {
    340     NSView *view = mouseDownViewIfStillGood();
    341     if (!view)
    342         return false;
    343 
    344     if (!m_mouseDownWasInSubframe) {
    345         ASSERT(!m_sendingEventToSubview);
    346         m_sendingEventToSubview = true;
    347         BEGIN_BLOCK_OBJC_EXCEPTIONS;
    348         [view mouseUp:currentNSEvent()];
    349         END_BLOCK_OBJC_EXCEPTIONS;
    350         m_sendingEventToSubview = false;
    351     }
    352 
    353     return true;
    354 }
    355 
    356 bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& event, Frame* subframe, HitTestResult* hoveredNode)
    357 {
    358     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    359 
    360     switch ([currentNSEvent() type]) {
    361         case NSLeftMouseDragged:
    362         case NSOtherMouseDragged:
    363         case NSRightMouseDragged:
    364             // This check is bogus and results in <rdar://6813830>, but removing it breaks a number of
    365             // layout tests.
    366             if (!m_mouseDownWasInSubframe)
    367                 return false;
    368 #if ENABLE(DRAG_SUPPORT)
    369             if (subframe->page()->dragController()->didInitiateDrag())
    370                 return false;
    371 #endif
    372         case NSMouseMoved:
    373             // Since we're passing in currentNSEvent() here, we can call
    374             // handleMouseMoveEvent() directly, since the save/restore of
    375             // currentNSEvent() that mouseMoved() does would have no effect.
    376             ASSERT(!m_sendingEventToSubview);
    377             m_sendingEventToSubview = true;
    378             subframe->eventHandler()->handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
    379             m_sendingEventToSubview = false;
    380             return true;
    381 
    382         case NSLeftMouseDown: {
    383             Node* node = event.targetNode();
    384             if (!node)
    385                 return false;
    386             RenderObject* renderer = node->renderer();
    387             if (!renderer || !renderer->isWidget())
    388                 return false;
    389             Widget* widget = toRenderWidget(renderer)->widget();
    390             if (!widget || !widget->isFrameView())
    391                 return false;
    392             if (!passWidgetMouseDownEventToWidget(toRenderWidget(renderer)))
    393                 return false;
    394             m_mouseDownWasInSubframe = true;
    395             return true;
    396         }
    397         case NSLeftMouseUp: {
    398             if (!m_mouseDownWasInSubframe)
    399                 return false;
    400             ASSERT(!m_sendingEventToSubview);
    401             m_sendingEventToSubview = true;
    402             subframe->eventHandler()->handleMouseReleaseEvent(currentPlatformMouseEvent());
    403             m_sendingEventToSubview = false;
    404             return true;
    405         }
    406         default:
    407             return false;
    408     }
    409     END_BLOCK_OBJC_EXCEPTIONS;
    410 
    411     return false;
    412 }
    413 
    414 static IMP originalNSScrollViewScrollWheel;
    415 static bool _nsScrollViewScrollWheelShouldRetainSelf;
    416 static void selfRetainingNSScrollViewScrollWheel(NSScrollView *, SEL, NSEvent *);
    417 
    418 static bool nsScrollViewScrollWheelShouldRetainSelf()
    419 {
    420     ASSERT(isMainThread());
    421 
    422     return _nsScrollViewScrollWheelShouldRetainSelf;
    423 }
    424 
    425 static void setNSScrollViewScrollWheelShouldRetainSelf(bool shouldRetain)
    426 {
    427     ASSERT(isMainThread());
    428 
    429     if (!originalNSScrollViewScrollWheel) {
    430         Method method = class_getInstanceMethod(objc_getRequiredClass("NSScrollView"), @selector(scrollWheel:));
    431         originalNSScrollViewScrollWheel = method_setImplementation(method, reinterpret_cast<IMP>(selfRetainingNSScrollViewScrollWheel));
    432     }
    433 
    434     _nsScrollViewScrollWheelShouldRetainSelf = shouldRetain;
    435 }
    436 
    437 static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selector, NSEvent *event)
    438 {
    439     bool shouldRetainSelf = isMainThread() && nsScrollViewScrollWheelShouldRetainSelf();
    440 
    441     if (shouldRetainSelf)
    442         [self retain];
    443     originalNSScrollViewScrollWheel(self, selector, event);
    444     if (shouldRetainSelf)
    445         [self release];
    446 }
    447 
    448 bool EventHandler::passWheelEventToWidget(PlatformWheelEvent&, Widget* widget)
    449 {
    450     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    451 
    452     if ([currentNSEvent() type] != NSScrollWheel || m_sendingEventToSubview || !widget)
    453         return false;
    454 
    455     NSView* nodeView = widget->platformWidget();
    456     ASSERT(nodeView);
    457     ASSERT([nodeView superview]);
    458     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:[currentNSEvent() locationInWindow] fromView:nil]];
    459     if (!view)
    460         // We probably hit the border of a RenderWidget
    461         return false;
    462 
    463     ASSERT(!m_sendingEventToSubview);
    464     m_sendingEventToSubview = true;
    465     // Work around <rdar://problem/6806810> which can cause -[NSScrollView scrollWheel:] to
    466     // crash if the NSScrollView is released during timer or network callback dispatch
    467     // in the nested tracking runloop that -[NSScrollView scrollWheel:] runs.
    468     setNSScrollViewScrollWheelShouldRetainSelf(true);
    469     [view scrollWheel:currentNSEvent()];
    470     setNSScrollViewScrollWheelShouldRetainSelf(false);
    471     m_sendingEventToSubview = false;
    472     return true;
    473 
    474     END_BLOCK_OBJC_EXCEPTIONS;
    475     return false;
    476 }
    477 
    478 void EventHandler::mouseDown(NSEvent *event)
    479 {
    480     FrameView* v = m_frame->view();
    481     if (!v || m_sendingEventToSubview)
    482         return;
    483 
    484     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    485 
    486     m_frame->loader()->resetMultipleFormSubmissionProtection();
    487 
    488     m_mouseDownView = nil;
    489 
    490     CurrentEventScope scope(event);
    491 
    492     handleMousePressEvent(currentPlatformMouseEvent());
    493 
    494     END_BLOCK_OBJC_EXCEPTIONS;
    495 }
    496 
    497 void EventHandler::mouseDragged(NSEvent *event)
    498 {
    499     FrameView* v = m_frame->view();
    500     if (!v || m_sendingEventToSubview)
    501         return;
    502 
    503     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    504 
    505     CurrentEventScope scope(event);
    506     handleMouseMoveEvent(currentPlatformMouseEvent());
    507 
    508     END_BLOCK_OBJC_EXCEPTIONS;
    509 }
    510 
    511 void EventHandler::mouseUp(NSEvent *event)
    512 {
    513     FrameView* v = m_frame->view();
    514     if (!v || m_sendingEventToSubview)
    515         return;
    516 
    517     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    518 
    519     CurrentEventScope scope(event);
    520 
    521     // Our behavior here is a little different that Qt. Qt always sends
    522     // a mouse release event, even for a double click. To correct problems
    523     // in khtml's DOM click event handling we do not send a release here
    524     // for a double click. Instead we send that event from FrameView's
    525     // handleMouseDoubleClickEvent. Note also that the third click of
    526     // a triple click is treated as a single click, but the fourth is then
    527     // treated as another double click. Hence the "% 2" below.
    528     int clickCount = [event clickCount];
    529     if (clickCount > 0 && clickCount % 2 == 0)
    530         handleMouseDoubleClickEvent(currentPlatformMouseEvent());
    531     else
    532         handleMouseReleaseEvent(currentPlatformMouseEvent());
    533 
    534     m_mouseDownView = nil;
    535 
    536     END_BLOCK_OBJC_EXCEPTIONS;
    537 }
    538 
    539 /*
    540  A hack for the benefit of AK's PopUpButton, which uses the Carbon menu manager, which thus
    541  eats all subsequent events after it is starts its modal tracking loop.  After the interaction
    542  is done, this routine is used to fix things up.  When a mouse down started us tracking in
    543  the widget, we post a fake mouse up to balance the mouse down we started with. When a
    544  key down started us tracking in the widget, we post a fake key up to balance things out.
    545  In addition, we post a fake mouseMoved to get the cursor in sync with whatever we happen to
    546  be over after the tracking is done.
    547  */
    548 void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *initiatingEvent)
    549 {
    550     FrameView* view = m_frame->view();
    551     if (!view)
    552         return;
    553 
    554     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    555 
    556     m_sendingEventToSubview = false;
    557     int eventType = [initiatingEvent type];
    558     if (eventType == NSLeftMouseDown || eventType == NSKeyDown) {
    559         NSEvent *fakeEvent = nil;
    560         if (eventType == NSLeftMouseDown) {
    561             fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
    562                                            location:[initiatingEvent locationInWindow]
    563                                       modifierFlags:[initiatingEvent modifierFlags]
    564                                           timestamp:[initiatingEvent timestamp]
    565                                        windowNumber:[initiatingEvent windowNumber]
    566                                             context:[initiatingEvent context]
    567                                         eventNumber:[initiatingEvent eventNumber]
    568                                          clickCount:[initiatingEvent clickCount]
    569                                            pressure:[initiatingEvent pressure]];
    570 
    571             [NSApp postEvent:fakeEvent atStart:YES];
    572         } else { // eventType == NSKeyDown
    573             fakeEvent = [NSEvent keyEventWithType:NSKeyUp
    574                                          location:[initiatingEvent locationInWindow]
    575                                     modifierFlags:[initiatingEvent modifierFlags]
    576                                         timestamp:[initiatingEvent timestamp]
    577                                      windowNumber:[initiatingEvent windowNumber]
    578                                           context:[initiatingEvent context]
    579                                        characters:[initiatingEvent characters]
    580                       charactersIgnoringModifiers:[initiatingEvent charactersIgnoringModifiers]
    581                                         isARepeat:[initiatingEvent isARepeat]
    582                                           keyCode:[initiatingEvent keyCode]];
    583             [NSApp postEvent:fakeEvent atStart:YES];
    584         }
    585         // FIXME: We should really get the current modifierFlags here, but there's no way to poll
    586         // them in Cocoa, and because the event stream was stolen by the Carbon menu code we have
    587         // no up-to-date cache of them anywhere.
    588         fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
    589                                        location:[[view->platformWidget() window] convertScreenToBase:[NSEvent mouseLocation]]
    590                                   modifierFlags:[initiatingEvent modifierFlags]
    591                                       timestamp:[initiatingEvent timestamp]
    592                                    windowNumber:[initiatingEvent windowNumber]
    593                                         context:[initiatingEvent context]
    594                                     eventNumber:0
    595                                      clickCount:0
    596                                        pressure:0];
    597         [NSApp postEvent:fakeEvent atStart:YES];
    598     }
    599 
    600     END_BLOCK_OBJC_EXCEPTIONS;
    601 }
    602 
    603 void EventHandler::mouseMoved(NSEvent *event)
    604 {
    605     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
    606     // These happen because WebKit sometimes has to fake up moved events.
    607     if (!m_frame->view() || m_mousePressed || m_sendingEventToSubview)
    608         return;
    609 
    610     BEGIN_BLOCK_OBJC_EXCEPTIONS;
    611     CurrentEventScope scope(event);
    612     mouseMoved(currentPlatformMouseEvent());
    613     END_BLOCK_OBJC_EXCEPTIONS;
    614 }
    615 
    616 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
    617 {
    618     return passSubframeEventToSubframe(mev, subframe);
    619 }
    620 
    621 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
    622 {
    623     return passSubframeEventToSubframe(mev, subframe, hoveredNode);
    624 }
    625 
    626 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
    627 {
    628     return passSubframeEventToSubframe(mev, subframe);
    629 }
    630 
    631 PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
    632 {
    633     NSView *windowView = nil;
    634     if (Page* page = m_frame->page())
    635         windowView = page->chrome()->platformPageClient();
    636     return PlatformMouseEvent(currentNSEvent(), windowView);
    637 }
    638 
    639 #if ENABLE(CONTEXT_MENUS)
    640 bool EventHandler::sendContextMenuEvent(NSEvent *event)
    641 {
    642     Page* page = m_frame->page();
    643     if (!page)
    644         return false;
    645     return sendContextMenuEvent(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
    646 }
    647 #endif // ENABLE(CONTEXT_MENUS)
    648 
    649 #if ENABLE(DRAG_SUPPORT)
    650 bool EventHandler::eventMayStartDrag(NSEvent *event)
    651 {
    652     Page* page = m_frame->page();
    653     if (!page)
    654         return false;
    655     return eventMayStartDrag(PlatformMouseEvent(event, page->chrome()->platformPageClient()));
    656 }
    657 #endif // ENABLE(DRAG_SUPPORT)
    658 
    659 bool EventHandler::eventActivatedView(const PlatformMouseEvent& event) const
    660 {
    661     return m_activationEventNumber == event.eventNumber();
    662 }
    663 
    664 #else // ENABLE(EXPERIMENTAL_SINGLE_VIEW_MODE)
    665 
    666 NSEvent *EventHandler::currentNSEvent()
    667 {
    668     return 0;
    669 }
    670 
    671 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
    672 {
    673     subframe->eventHandler()->handleMousePressEvent(mev.event());
    674     return true;
    675 }
    676 
    677 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
    678 {
    679     if (m_mouseDownMayStartDrag && !m_mouseDownWasInSubframe)
    680         return false;
    681     subframe->eventHandler()->handleMouseMoveEvent(mev.event(), hoveredNode);
    682     return true;
    683 }
    684 
    685 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
    686 {
    687     subframe->eventHandler()->handleMouseReleaseEvent(mev.event());
    688     return true;
    689 }
    690 
    691 bool EventHandler::passWheelEventToWidget(PlatformWheelEvent& wheelEvent, Widget* widget)
    692 {
    693     if (!widget->isFrameView())
    694         return false;
    695 
    696     return static_cast<FrameView*>(widget)->frame()->eventHandler()->handleWheelEvent(wheelEvent);
    697 }
    698 
    699 void EventHandler::focusDocumentView()
    700 {
    701     Page* page = m_frame->page();
    702     if (!page)
    703         return;
    704     page->focusController()->setFocusedFrame(m_frame);
    705 }
    706 
    707 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults&)
    708 {
    709     notImplemented();
    710     return false;
    711 }
    712 
    713 bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
    714 {
    715     notImplemented();
    716     return false;
    717 }
    718 
    719 PassRefPtr<KeyboardEvent> EventHandler::currentKeyboardEvent() const
    720 {
    721     return 0;
    722 }
    723 
    724 void EventHandler::mouseDown(NSEvent *)
    725 {
    726     notImplemented();
    727 }
    728 
    729 void EventHandler::mouseDragged(NSEvent *)
    730 {
    731     notImplemented();
    732 }
    733 
    734 void EventHandler::mouseUp(NSEvent *)
    735 {
    736     notImplemented();
    737 }
    738 
    739 void EventHandler::mouseMoved(NSEvent *)
    740 {
    741     notImplemented();
    742 }
    743 
    744 bool EventHandler::keyEvent(NSEvent *)
    745 {
    746     notImplemented();
    747     return false;
    748 }
    749 
    750 bool EventHandler::wheelEvent(NSEvent *)
    751 {
    752     notImplemented();
    753     return false;
    754 }
    755 
    756 #if ENABLE(CONTEXT_MENUS)
    757 bool EventHandler::sendContextMenuEvent(NSEvent *)
    758 {
    759     notImplemented();
    760     return false;
    761 }
    762 #endif
    763 
    764 bool EventHandler::eventMayStartDrag(NSEvent *)
    765 {
    766     notImplemented();
    767     return false;
    768 }
    769 
    770 void EventHandler::sendFakeEventsAfterWidgetTracking(NSEvent *)
    771 {
    772 }
    773 
    774 
    775 #endif
    776 
    777 #if ENABLE(DRAG_SUPPORT)
    778 
    779 PassRefPtr<Clipboard> EventHandler::createDraggingClipboard() const
    780 {
    781     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
    782     // Must be done before ondragstart adds types and data to the pboard,
    783     // also done for security, as it erases data from the last drag
    784     [pasteboard declareTypes:[NSArray array] owner:nil];
    785     return ClipboardMac::create(true, pasteboard, ClipboardWritable, m_frame);
    786 }
    787 
    788 #endif
    789 
    790 static inline bool isKeyboardOptionTab(KeyboardEvent* event)
    791 {
    792     return event
    793         && (event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent)
    794         && event->altKey()
    795         && event->keyIdentifier() == "U+0009";
    796 }
    797 
    798 bool EventHandler::invertSenseOfTabsToLinks(KeyboardEvent* event) const
    799 {
    800     return isKeyboardOptionTab(event);
    801 }
    802 
    803 bool EventHandler::tabsToAllControls(KeyboardEvent* event) const
    804 {
    805     Page* page = m_frame->page();
    806     if (!page)
    807         return false;
    808 
    809     KeyboardUIMode keyboardUIMode = page->chrome()->client()->keyboardUIMode();
    810     bool handlingOptionTab = isKeyboardOptionTab(event);
    811 
    812     // If tab-to-links is off, option-tab always highlights all controls
    813     if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
    814         return true;
    815 
    816     // If system preferences say to include all controls, we always include all controls
    817     if (keyboardUIMode & KeyboardAccessFull)
    818         return true;
    819 
    820     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
    821     if (keyboardUIMode & KeyboardAccessTabsToLinks)
    822         return !handlingOptionTab;
    823 
    824     return handlingOptionTab;
    825 }
    826 
    827 bool EventHandler::needsKeyboardEventDisambiguationQuirks() const
    828 {
    829     Document* document = m_frame->document();
    830 
    831     // RSS view needs arrow key keypress events.
    832     if (applicationIsSafari() && document->url().protocolIs("feed") || document->url().protocolIs("feeds"))
    833         return true;
    834     Settings* settings = m_frame->settings();
    835     if (!settings)
    836         return false;
    837 
    838 #if ENABLE(DASHBOARD_SUPPORT)
    839     if (settings->usesDashboardBackwardCompatibilityMode())
    840         return true;
    841 #endif
    842 
    843     if (settings->needsKeyboardEventDisambiguationQuirks())
    844         return true;
    845 
    846     return false;
    847 }
    848 
    849 unsigned EventHandler::accessKeyModifiers()
    850 {
    851     // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
    852     // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
    853     // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
    854     if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
    855         return PlatformKeyboardEvent::CtrlKey;
    856 
    857     return PlatformKeyboardEvent::CtrlKey | PlatformKeyboardEvent::AltKey;
    858 }
    859 
    860 }
    861