87cb5cce9d0a7787778418de2875d719a464c458
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / EventDispatcher.cpp
1 /*
2  * Copyright (C) 2011, 2014 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "EventDispatcher.h"
28
29 #include "EventDispatcherMessages.h"
30 #include "WebEvent.h"
31 #include "WebEventConversion.h"
32 #include "WebPage.h"
33 #include "WebPageProxyMessages.h"
34 #include "WebProcess.h"
35 #include <WebCore/Page.h>
36 #include <wtf/MainThread.h>
37 #include <wtf/RunLoop.h>
38
39 #if ENABLE(ASYNC_SCROLLING)
40 #include <WebCore/AsyncScrollingCoordinator.h>
41 #include <WebCore/ScrollingThread.h>
42 #include <WebCore/ThreadedScrollingTree.h>
43 #endif
44
45 using namespace WebCore;
46
47 namespace WebKit {
48
49 PassRefPtr<EventDispatcher> EventDispatcher::create()
50 {
51     return adoptRef(new EventDispatcher);
52 }
53
54 EventDispatcher::EventDispatcher()
55     : m_queue(WorkQueue::create("com.apple.WebKit.EventDispatcher", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive))
56     , m_recentWheelEventDeltaTracker(std::make_unique<WheelEventDeltaTracker>())
57 {
58 }
59
60 EventDispatcher::~EventDispatcher()
61 {
62 }
63
64 #if ENABLE(ASYNC_SCROLLING)
65 void EventDispatcher::addScrollingTreeForPage(WebPage* webPage)
66 {
67     MutexLocker locker(m_scrollingTreesMutex);
68
69     ASSERT(webPage->corePage()->scrollingCoordinator());
70     ASSERT(!m_scrollingTrees.contains(webPage->pageID()));
71
72     AsyncScrollingCoordinator& scrollingCoordinator = downcast<AsyncScrollingCoordinator>(*webPage->corePage()->scrollingCoordinator());
73     m_scrollingTrees.set(webPage->pageID(), downcast<ThreadedScrollingTree>(scrollingCoordinator.scrollingTree()));
74 }
75
76 void EventDispatcher::removeScrollingTreeForPage(WebPage* webPage)
77 {
78     MutexLocker locker(m_scrollingTreesMutex);
79     ASSERT(m_scrollingTrees.contains(webPage->pageID()));
80
81     m_scrollingTrees.remove(webPage->pageID());
82 }
83 #endif
84
85 void EventDispatcher::initializeConnection(IPC::Connection* connection)
86 {
87     connection->addWorkQueueMessageReceiver(Messages::EventDispatcher::messageReceiverName(), &m_queue.get(), this);
88 }
89
90 void EventDispatcher::wheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent, bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom)
91 {
92     PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
93
94 #if PLATFORM(COCOA)
95     switch (wheelEvent.phase()) {
96     case PlatformWheelEventPhaseBegan:
97         m_recentWheelEventDeltaTracker->beginTrackingDeltas();
98         break;
99     case PlatformWheelEventPhaseEnded:
100         m_recentWheelEventDeltaTracker->endTrackingDeltas();
101         break;
102     default:
103         break;
104     }
105
106     if (m_recentWheelEventDeltaTracker->isTrackingDeltas()) {
107         m_recentWheelEventDeltaTracker->recordWheelEventDelta(platformWheelEvent);
108
109         DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None;
110         dominantDirection = m_recentWheelEventDeltaTracker->dominantScrollGestureDirection();
111
112         // Workaround for scrolling issues <rdar://problem/14758615>.
113         if (dominantDirection == DominantScrollGestureDirection::Vertical && platformWheelEvent.deltaX())
114             platformWheelEvent = platformWheelEvent.copyIgnoringHorizontalDelta();
115         else if (dominantDirection == DominantScrollGestureDirection::Horizontal && platformWheelEvent.deltaY())
116             platformWheelEvent = platformWheelEvent.copyIgnoringVerticalDelta();
117     }
118 #endif
119
120 #if ENABLE(ASYNC_SCROLLING)
121     MutexLocker locker(m_scrollingTreesMutex);
122     if (RefPtr<ThreadedScrollingTree> scrollingTree = m_scrollingTrees.get(pageID)) {
123         // FIXME: It's pretty horrible that we're updating the back/forward state here.
124         // WebCore should always know the current state and know when it changes so the
125         // scrolling tree can be notified.
126         // We only need to do this at the beginning of the gesture.
127         if (platformWheelEvent.phase() == PlatformWheelEventPhaseBegan) {
128             ScrollingThread::dispatch([scrollingTree, canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom] {
129                 scrollingTree->setCanRubberBandState(canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom);
130             });
131         }
132
133         ScrollingTree::EventResult result = scrollingTree->tryToHandleWheelEvent(platformWheelEvent);
134         if (result == ScrollingTree::DidHandleEvent || result == ScrollingTree::DidNotHandleEvent) {
135             sendDidReceiveEvent(pageID, wheelEvent, result == ScrollingTree::DidHandleEvent);
136             return;
137         }
138     }
139 #else
140     UNUSED_PARAM(canRubberBandAtLeft);
141     UNUSED_PARAM(canRubberBandAtRight);
142     UNUSED_PARAM(canRubberBandAtTop);
143     UNUSED_PARAM(canRubberBandAtBottom);
144 #endif
145
146     RefPtr<EventDispatcher> eventDispatcher(this);
147     RunLoop::main().dispatch([eventDispatcher, pageID, wheelEvent] {
148         eventDispatcher->dispatchWheelEvent(pageID, wheelEvent);
149     }); 
150 }
151
152 #if ENABLE(IOS_TOUCH_EVENTS)
153 void EventDispatcher::clearQueuedTouchEventsForPage(const WebPage& webPage)
154 {
155     SpinLockHolder locker(&m_touchEventsLock);
156     m_touchEvents.remove(webPage.pageID());
157 }
158
159 void EventDispatcher::getQueuedTouchEventsForPage(const WebPage& webPage, TouchEventQueue& destinationQueue)
160 {
161     SpinLockHolder locker(&m_touchEventsLock);
162     destinationQueue = m_touchEvents.take(webPage.pageID());
163 }
164
165 void EventDispatcher::touchEvent(uint64_t pageID, const WebKit::WebTouchEvent& touchEvent)
166 {
167     bool updateListWasEmpty;
168     {
169         SpinLockHolder locker(&m_touchEventsLock);
170         updateListWasEmpty = m_touchEvents.isEmpty();
171         auto addResult = m_touchEvents.add(pageID, TouchEventQueue());
172         if (addResult.isNewEntry)
173             addResult.iterator->value.append(touchEvent);
174         else {
175             TouchEventQueue& queuedEvents = addResult.iterator->value;
176             ASSERT(!queuedEvents.isEmpty());
177             const WebTouchEvent& lastTouchEvent = queuedEvents.last();
178
179             // Coalesce touch move events.
180             WebEvent::Type type = lastTouchEvent.type();
181             if (type == WebEvent::TouchMove)
182                 queuedEvents.last() = touchEvent;
183             else
184                 queuedEvents.append(touchEvent);
185         }
186     }
187
188     if (updateListWasEmpty) {
189         RefPtr<EventDispatcher> eventDispatcher(this);
190         RunLoop::main().dispatch([eventDispatcher] {
191             eventDispatcher->dispatchTouchEvents();
192         });
193     }
194 }
195
196 void EventDispatcher::dispatchTouchEvents()
197 {
198     HashMap<uint64_t, TouchEventQueue> localCopy;
199     {
200         SpinLockHolder locker(&m_touchEventsLock);
201         localCopy.swap(m_touchEvents);
202     }
203
204     for (auto& slot : localCopy) {
205         if (WebPage* webPage = WebProcess::singleton().webPage(slot.key))
206             webPage->dispatchAsynchronousTouchEvents(slot.value);
207     }
208 }
209 #endif
210
211 void EventDispatcher::dispatchWheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent)
212 {
213     ASSERT(RunLoop::isMain());
214
215     WebPage* webPage = WebProcess::singleton().webPage(pageID);
216     if (!webPage)
217         return;
218
219     webPage->wheelEvent(wheelEvent);
220 }
221
222 #if ENABLE(ASYNC_SCROLLING)
223 void EventDispatcher::sendDidReceiveEvent(uint64_t pageID, const WebEvent& event, bool didHandleEvent)
224 {
225     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(event.type()), didHandleEvent), pageID);
226 }
227 #endif
228
229 } // namespace WebKit