Remove PassRefPtr from "page" directory of WebCore, also deploy references
[WebKit-https.git] / Source / WebCore / page / ios / EventHandlerIOS.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 #import "config.h"
27 #import "EventHandler.h"
28
29 #import "AXObjectCache.h"
30 #import "Chrome.h"
31 #import "ChromeClient.h"
32 #import "FocusController.h"
33 #import "Frame.h"
34 #import "FrameView.h"
35 #import "KeyboardEvent.h"
36 #import "MouseEventWithHitTestResults.h"
37 #import "Page.h"
38 #import "PlatformEventFactoryIOS.h"
39 #import "PlatformKeyboardEvent.h"
40 #import "RenderWidget.h"
41 #import "WAKView.h"
42 #import "WAKWindow.h"
43 #import "WebEvent.h"
44 #import <wtf/BlockObjCExceptions.h>
45 #import <wtf/NeverDestroyed.h>
46 #import <wtf/Noncopyable.h>
47
48 #if ENABLE(IOS_TOUCH_EVENTS)
49 #import <WebKitAdditions/EventHandlerIOSTouch.cpp>
50 #endif
51
52 namespace WebCore {
53
54 static RetainPtr<WebEvent>& currentEventSlot()
55 {
56     static NeverDestroyed<RetainPtr<WebEvent>> event;
57     return event;
58 }
59
60 WebEvent *EventHandler::currentEvent()
61 {
62     return currentEventSlot().get();
63 }
64
65 class CurrentEventScope {
66     WTF_MAKE_NONCOPYABLE(CurrentEventScope);
67 public:
68     CurrentEventScope(WebEvent *);
69     ~CurrentEventScope();
70
71 private:
72     RetainPtr<WebEvent> m_savedCurrentEvent;
73 #ifndef NDEBUG
74     RetainPtr<WebEvent> m_event;
75 #endif
76 };
77
78 inline CurrentEventScope::CurrentEventScope(WebEvent *event)
79     : m_savedCurrentEvent(currentEventSlot())
80 #ifndef NDEBUG
81     , m_event(event)
82 #endif
83 {
84     currentEventSlot() = event;
85 }
86
87 inline CurrentEventScope::~CurrentEventScope()
88 {
89     ASSERT(currentEventSlot() == m_event);
90     currentEventSlot() = m_savedCurrentEvent;
91 }
92
93 bool EventHandler::wheelEvent(WebEvent *event)
94 {
95     Page* page = m_frame.page();
96     if (!page)
97         return false;
98
99     CurrentEventScope scope(event);
100
101     bool eventWasHandled = handleWheelEvent(PlatformEventFactory::createPlatformWheelEvent(event));
102     event.wasHandled = eventWasHandled;
103     return eventWasHandled;
104 }
105
106 #if ENABLE(IOS_TOUCH_EVENTS)
107
108 bool EventHandler::dispatchSimulatedTouchEvent(IntPoint location)
109 {
110     bool handled = handleTouchEvent(PlatformEventFactory::createPlatformSimulatedTouchEvent(PlatformEvent::TouchStart, location));
111     handled |= handleTouchEvent(PlatformEventFactory::createPlatformSimulatedTouchEvent(PlatformEvent::TouchEnd, location));
112     return handled;
113 }
114     
115 void EventHandler::touchEvent(WebEvent *event)
116 {
117     CurrentEventScope scope(event);
118
119     event.wasHandled = handleTouchEvent(PlatformEventFactory::createPlatformTouchEvent(event));
120 }
121 #endif
122
123 bool EventHandler::tabsToAllFormControls(KeyboardEvent& event) const
124 {
125     Page* page = m_frame.page();
126     if (!page)
127         return false;
128
129     KeyboardUIMode keyboardUIMode = page->chrome().client().keyboardUIMode();
130     bool handlingOptionTab = isKeyboardOptionTab(event);
131
132     // If tab-to-links is off, option-tab always highlights all controls.
133     if ((keyboardUIMode & KeyboardAccessTabsToLinks) == 0 && handlingOptionTab)
134         return true;
135
136     // If system preferences say to include all controls, we always include all controls.
137     if (keyboardUIMode & KeyboardAccessFull)
138         return true;
139
140     // Otherwise tab-to-links includes all controls, unless the sense is flipped via option-tab.
141     if (keyboardUIMode & KeyboardAccessTabsToLinks)
142         return !handlingOptionTab;
143
144     return handlingOptionTab;
145 }
146
147 bool EventHandler::keyEvent(WebEvent *event)
148 {
149     BEGIN_BLOCK_OBJC_EXCEPTIONS;
150
151     ASSERT(event.type == WebEventKeyDown || event.type == WebEventKeyUp);
152
153     CurrentEventScope scope(event);
154     bool eventWasHandled = keyEvent(PlatformEventFactory::createPlatformKeyboardEvent(event));
155     event.wasHandled = eventWasHandled;
156     return eventWasHandled;
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     Ref<Frame> protectedFrame(m_frame);
170
171     if (FrameView* frameView = m_frame.view()) {
172         if (NSView *documentView = frameView->documentView())
173             page->chrome().focusNSView(documentView);
174     }
175
176     page->focusController().setFocusedFrame(&m_frame);
177 }
178
179 bool EventHandler::passWidgetMouseDownEventToWidget(const MouseEventWithHitTestResults& event)
180 {
181     // Figure out which view to send the event to.
182     auto* target = event.targetNode() ? event.targetNode()->renderer() : nullptr;
183     if (!is<RenderWidget>(target))
184         return false;
185
186     // Double-click events don't exist in Cocoa. Since passWidgetMouseDownEventToWidget() will
187     // just pass currentEvent down to the widget, we don't want to call it for events that
188     // don't correspond to Cocoa events. The mousedown/ups will have already been passed on as
189     // part of the pressed/released handling.
190     return passMouseDownEventToWidget(downcast<RenderWidget>(*target).widget());
191 }
192
193 bool EventHandler::passWidgetMouseDownEventToWidget(RenderWidget* renderWidget)
194 {
195     return passMouseDownEventToWidget(renderWidget->widget());
196 }
197
198 static bool lastEventIsMouseUp()
199 {
200     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
201     // When they finish, currentEvent is the mouseUp that they exited on. We need to update
202     // the WebCore state with this mouseUp, which we never saw. This method lets us detect
203     // that state. Handling this was critical when we used AppKit widgets for form elements.
204     // It's not clear in what cases this is helpful now -- it's possible it can be removed. 
205
206     BEGIN_BLOCK_OBJC_EXCEPTIONS;
207     WebEvent *currentEventAfterHandlingMouseDown = [WAKWindow currentEvent];
208     return currentEventAfterHandlingMouseDown
209         && EventHandler::currentEvent() != currentEventAfterHandlingMouseDown
210         && currentEventAfterHandlingMouseDown.type == WebEventMouseUp
211         && currentEventAfterHandlingMouseDown.timestamp >= EventHandler::currentEvent().timestamp;
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);
238     ASSERT([nodeView superview]);
239     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:currentEvent().locationInWindow fromView:nil]];
240     if (!view) {
241         // We probably hit the border of a RenderWidget
242         return true;
243     }
244
245     Page* page = m_frame.page();
246     if (!page)
247         return true;
248
249     if (page->chrome().client().firstResponder() != view) {
250         // Normally [NSWindow sendEvent:] handles setting the first responder.
251         // But in our case, the event was sent to the view representing the entire web page.
252         if ([view acceptsFirstResponder] && [view needsPanelToBecomeKey])
253             page->chrome().client().makeFirstResponder(view);
254     }
255
256     // We need to "defer loading" while tracking the mouse, because tearing down the
257     // page while an AppKit control is tracking the mouse can cause a crash.
258
259     // FIXME: In theory, WebCore now tolerates tear-down while tracking the
260     // mouse. We should confirm that, and then remove the deferrsLoading
261     // hack entirely.
262
263     bool wasDeferringLoading = page->defersLoading();
264     if (!wasDeferringLoading)
265         page->setDefersLoading(true);
266
267     ASSERT(!m_sendingEventToSubview);
268     m_sendingEventToSubview = true;
269
270     {
271         WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
272         [view mouseDown:currentEvent()];
273     }
274
275     m_sendingEventToSubview = false;
276     
277     if (!wasDeferringLoading)
278         page->setDefersLoading(false);
279
280     // Remember which view we sent the event to, so we can direct the release event properly.
281     m_mouseDownView = view;
282     m_mouseDownWasInSubframe = false;
283
284     // Many AppKit widgets run their own event loops and consume events while the mouse is down.
285     // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
286     // the EventHandler state with this mouseUp, which we never saw.
287     // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
288     // is a hole here if the widget consumes both the mouseUp and subsequent events.
289     if (lastEventIsMouseUp())
290         m_mousePressed = false;
291
292     END_BLOCK_OBJC_EXCEPTIONS;
293
294     return true;
295 }
296
297 // Note that this does the same kind of check as [target isDescendantOf:superview].
298 // There are two differences: This is a lot slower because it has to walk the whole
299 // tree, and this works in cases where the target has already been deallocated.
300 static bool findViewInSubviews(NSView *superview, NSView *target)
301 {
302     BEGIN_BLOCK_OBJC_EXCEPTIONS;
303     NSEnumerator *e = [[superview subviews] objectEnumerator];
304     NSView *subview;
305     while ((subview = [e nextObject])) {
306         if (subview == target || findViewInSubviews(subview, target)) {
307             return true;
308         }
309     }
310     END_BLOCK_OBJC_EXCEPTIONS;
311
312     return false;
313 }
314
315 NSView *EventHandler::mouseDownViewIfStillGood()
316 {
317     // Since we have no way of tracking the lifetime of m_mouseDownView, we have to assume that
318     // it could be deallocated already. We search for it in our subview tree; if we don't find
319     // it, we set it to nil.
320     NSView *mouseDownView = m_mouseDownView;
321     if (!mouseDownView) {
322         return nil;
323     }
324     FrameView* topFrameView = m_frame.view();
325     NSView *topView = topFrameView ? topFrameView->platformWidget() : nil;
326     if (!topView || !findViewInSubviews(topView, mouseDownView)) {
327         m_mouseDownView = nil;
328         return nil;
329     }
330     return mouseDownView;
331 }
332
333 bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
334 {
335     return false;
336 }
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:currentEvent()];
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     WebEventType currentEventType = currentEvent().type;
361     switch (currentEventType) {
362         case WebEventMouseMoved: {
363             // Since we're passing in currentNSEvent() here, we can call
364             // handleMouseMoveEvent() directly, since the save/restore of
365             // currentNSEvent() that mouseMoved() does would have no effect.
366             ASSERT(!m_sendingEventToSubview);
367             m_sendingEventToSubview = true;
368             subframe->eventHandler().handleMouseMoveEvent(currentPlatformMouseEvent(), hoveredNode);
369             m_sendingEventToSubview = false;
370             return true;
371         }
372         case WebEventMouseDown: {
373             Node* node = event.targetNode();
374             if (!node)
375                 return false;
376             auto* renderer = node->renderer();
377             if (!is<RenderWidget>(renderer))
378                 return false;
379             Widget* widget = downcast<RenderWidget>(*renderer).widget();
380             if (!widget || !widget->isFrameView())
381                 return false;
382             if (!passWidgetMouseDownEventToWidget(downcast<RenderWidget>(renderer)))
383                 return false;
384             m_mouseDownWasInSubframe = true;
385             return true;
386         }
387         case WebEventMouseUp: {
388             if (!m_mouseDownWasInSubframe)
389                 return false;
390             ASSERT(!m_sendingEventToSubview);
391             m_sendingEventToSubview = true;
392             subframe->eventHandler().handleMouseReleaseEvent(currentPlatformMouseEvent());
393             m_sendingEventToSubview = false;
394             return true;
395         }
396         case WebEventKeyDown:
397         case WebEventKeyUp:
398         case WebEventScrollWheel:
399         case WebEventTouchBegin:
400         case WebEventTouchCancel:
401         case WebEventTouchChange:
402         case WebEventTouchEnd:
403             return false;
404     }
405     END_BLOCK_OBJC_EXCEPTIONS;
406
407     return false;
408 }
409
410 bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent&, Widget& widget)
411 {
412     BEGIN_BLOCK_OBJC_EXCEPTIONS;
413
414     NSView* nodeView = widget.platformWidget();
415     if (!nodeView) {
416         // WK2 code path. No wheel events on iOS anyway.
417         return false;
418     }
419
420     if (currentEvent().type != WebEventScrollWheel || m_sendingEventToSubview)
421         return false;
422
423     ASSERT(nodeView);
424     ASSERT([nodeView superview]);
425     NSView *view = [nodeView hitTest:[[nodeView superview] convertPoint:currentEvent().locationInWindow fromView:nil]];
426     if (!view) {
427         // We probably hit the border of a RenderWidget
428         return false;
429     }
430
431     ASSERT(!m_sendingEventToSubview);
432     m_sendingEventToSubview = true;
433     [view scrollWheel:currentEvent()];
434     m_sendingEventToSubview = false;
435     return true;
436
437     END_BLOCK_OBJC_EXCEPTIONS;
438     return false;
439 }
440
441 void EventHandler::mouseDown(WebEvent *event)
442 {
443     FrameView* v = m_frame.view();
444     if (!v || m_sendingEventToSubview)
445         return;
446
447     BEGIN_BLOCK_OBJC_EXCEPTIONS;
448
449     // FIXME: Why is this here? EventHandler::handleMousePressEvent() calls it.
450     m_frame.loader().resetMultipleFormSubmissionProtection();
451
452     m_mouseDownView = nil;
453
454     CurrentEventScope scope(event);
455
456     event.wasHandled = handleMousePressEvent(currentPlatformMouseEvent());
457
458     END_BLOCK_OBJC_EXCEPTIONS;
459 }
460
461 void EventHandler::mouseUp(WebEvent *event)
462 {
463     FrameView* v = m_frame.view();
464     if (!v || m_sendingEventToSubview)
465         return;
466
467     BEGIN_BLOCK_OBJC_EXCEPTIONS;
468
469     CurrentEventScope scope(event);
470
471     event.wasHandled = handleMouseReleaseEvent(currentPlatformMouseEvent());
472
473     m_mouseDownView = nil;
474
475     END_BLOCK_OBJC_EXCEPTIONS;
476 }
477
478 void EventHandler::mouseMoved(WebEvent *event)
479 {
480     // Reject a mouse moved if the button is down - screws up tracking during autoscroll
481     // These happen because WebKit sometimes has to fake up moved events.
482     if (!m_frame.view() || m_mousePressed || m_sendingEventToSubview)
483         return;
484
485     BEGIN_BLOCK_OBJC_EXCEPTIONS;
486
487     m_frame.document()->updateStyleIfNeeded();
488
489     WKBeginObservingContentChanges(true);
490     CurrentEventScope scope(event);
491     event.wasHandled = mouseMoved(currentPlatformMouseEvent());
492     
493     // FIXME: Why is this here?
494     m_frame.document()->updateStyleIfNeeded();
495     WKStopObservingContentChanges();
496
497     END_BLOCK_OBJC_EXCEPTIONS;
498 }
499
500 static bool frameHasPlatformWidget(const Frame& frame)
501 {
502     if (FrameView* frameView = frame.view()) {
503         if (frameView->platformWidget())
504             return true;
505     }
506
507     return false;
508 }
509
510 bool EventHandler::passMousePressEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
511 {
512     // WebKit1 code path.
513     if (frameHasPlatformWidget(m_frame))
514         return passSubframeEventToSubframe(mev, subframe);
515
516     // WebKit2 code path.
517     subframe->eventHandler().handleMousePressEvent(mev.event());
518     return true;
519 }
520
521 bool EventHandler::passMouseMoveEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe, HitTestResult* hoveredNode)
522 {
523     // WebKit1 code path.
524     if (frameHasPlatformWidget(m_frame))
525         return passSubframeEventToSubframe(mev, subframe, hoveredNode);
526
527     subframe->eventHandler().handleMouseMoveEvent(mev.event(), hoveredNode);
528     return true;
529 }
530
531 bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults& mev, Frame* subframe)
532 {
533     // WebKit1 code path.
534     if (frameHasPlatformWidget(m_frame))
535         return passSubframeEventToSubframe(mev, subframe);
536
537     // WebKit2 code path.
538     subframe->eventHandler().handleMouseReleaseEvent(mev.event());
539     return true;
540 }
541
542 OptionSet<PlatformEvent::Modifier> EventHandler::accessKeyModifiers()
543 {
544     // Control+Option key combinations are usually unused on Mac OS X, but not when VoiceOver is enabled.
545     // So, we use Control in this case, even though it conflicts with Emacs-style key bindings.
546     // See <https://bugs.webkit.org/show_bug.cgi?id=21107> for more detail.
547     if (AXObjectCache::accessibilityEnhancedUserInterfaceEnabled())
548         return PlatformEvent::Modifier::CtrlKey;
549
550     return { PlatformEvent::Modifier::CtrlKey, PlatformEvent::Modifier::AltKey };
551 }
552
553 PlatformMouseEvent EventHandler::currentPlatformMouseEvent() const
554 {
555     return PlatformEventFactory::createPlatformMouseEvent(currentEvent());
556 }
557
558 }