f457abf1967ca652e833757e7c247617d76ce0eb
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / EventDispatcher.cpp
1 /*
2  * Copyright (C) 2011, 2014-2015 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 <WebCore/WheelEventTestTrigger.h>
37 #include <wtf/MainThread.h>
38 #include <wtf/RunLoop.h>
39
40 #if ENABLE(ASYNC_SCROLLING)
41 #include <WebCore/AsyncScrollingCoordinator.h>
42 #include <WebCore/ScrollingThread.h>
43 #include <WebCore/ThreadedScrollingTree.h>
44 #endif
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 Ref<EventDispatcher> EventDispatcher::create()
51 {
52     return adoptRef(*new EventDispatcher);
53 }
54
55 EventDispatcher::EventDispatcher()
56     : m_queue(WorkQueue::create("com.apple.WebKit.EventDispatcher", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive))
57     , m_recentWheelEventDeltaTracker(std::make_unique<WheelEventDeltaTracker>())
58 {
59 }
60
61 EventDispatcher::~EventDispatcher()
62 {
63 }
64
65 #if ENABLE(ASYNC_SCROLLING)
66 void EventDispatcher::addScrollingTreeForPage(WebPage* webPage)
67 {
68     DeprecatedMutexLocker locker(m_scrollingTreesMutex);
69
70     ASSERT(webPage->corePage()->scrollingCoordinator());
71     ASSERT(!m_scrollingTrees.contains(webPage->pageID()));
72
73     AsyncScrollingCoordinator& scrollingCoordinator = downcast<AsyncScrollingCoordinator>(*webPage->corePage()->scrollingCoordinator());
74     m_scrollingTrees.set(webPage->pageID(), downcast<ThreadedScrollingTree>(scrollingCoordinator.scrollingTree()));
75 }
76
77 void EventDispatcher::removeScrollingTreeForPage(WebPage* webPage)
78 {
79     DeprecatedMutexLocker locker(m_scrollingTreesMutex);
80     ASSERT(m_scrollingTrees.contains(webPage->pageID()));
81
82     m_scrollingTrees.remove(webPage->pageID());
83 }
84 #endif
85
86 void EventDispatcher::initializeConnection(IPC::Connection* connection)
87 {
88     connection->addWorkQueueMessageReceiver(Messages::EventDispatcher::messageReceiverName(), &m_queue.get(), this);
89 }
90
91 #if ENABLE(CSS_SCROLL_SNAP) || ENABLE(RUBBER_BANDING)
92 static void updateWheelEventTestTriggersIfNeeded(uint64_t pageID)
93 {
94     WebPage* webPage = WebProcess::singleton().webPage(pageID);
95     Page* page = webPage ? webPage->corePage() : nullptr;
96
97     if (!page || !page->expectsWheelEventTriggers())
98         return;
99
100     page->testTrigger()->deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(page), WheelEventTestTrigger::ScrollingThreadSyncNeeded);
101 }
102 #endif
103
104 void EventDispatcher::wheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent, bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom)
105 {
106     PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
107
108 #if PLATFORM(COCOA)
109     switch (wheelEvent.phase()) {
110     case PlatformWheelEventPhaseBegan:
111         m_recentWheelEventDeltaTracker->beginTrackingDeltas();
112         break;
113     case PlatformWheelEventPhaseEnded:
114         m_recentWheelEventDeltaTracker->endTrackingDeltas();
115         break;
116     default:
117         break;
118     }
119
120     if (m_recentWheelEventDeltaTracker->isTrackingDeltas()) {
121         m_recentWheelEventDeltaTracker->recordWheelEventDelta(platformWheelEvent);
122
123         DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None;
124         dominantDirection = m_recentWheelEventDeltaTracker->dominantScrollGestureDirection();
125
126         // Workaround for scrolling issues <rdar://problem/14758615>.
127         if (dominantDirection == DominantScrollGestureDirection::Vertical && platformWheelEvent.deltaX())
128             platformWheelEvent = platformWheelEvent.copyIgnoringHorizontalDelta();
129         else if (dominantDirection == DominantScrollGestureDirection::Horizontal && platformWheelEvent.deltaY())
130             platformWheelEvent = platformWheelEvent.copyIgnoringVerticalDelta();
131     }
132 #endif
133
134 #if ENABLE(ASYNC_SCROLLING)
135     DeprecatedMutexLocker locker(m_scrollingTreesMutex);
136     if (RefPtr<ThreadedScrollingTree> scrollingTree = m_scrollingTrees.get(pageID)) {
137         // FIXME: It's pretty horrible that we're updating the back/forward state here.
138         // WebCore should always know the current state and know when it changes so the
139         // scrolling tree can be notified.
140         // We only need to do this at the beginning of the gesture.
141         if (platformWheelEvent.phase() == PlatformWheelEventPhaseBegan) {
142             ScrollingThread::dispatch([scrollingTree, canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom] {
143                 scrollingTree->setCanRubberBandState(canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom);
144             });
145         }
146
147         ScrollingTree::EventResult result = scrollingTree->tryToHandleWheelEvent(platformWheelEvent);
148
149 #if ENABLE(CSS_SCROLL_SNAP) || ENABLE(RUBBER_BANDING)
150         if (result == ScrollingTree::DidHandleEvent)
151             updateWheelEventTestTriggersIfNeeded(pageID);
152 #endif
153
154         if (result == ScrollingTree::DidHandleEvent || result == ScrollingTree::DidNotHandleEvent) {
155             sendDidReceiveEvent(pageID, wheelEvent, result == ScrollingTree::DidHandleEvent);
156             return;
157         }
158     }
159 #else
160     UNUSED_PARAM(canRubberBandAtLeft);
161     UNUSED_PARAM(canRubberBandAtRight);
162     UNUSED_PARAM(canRubberBandAtTop);
163     UNUSED_PARAM(canRubberBandAtBottom);
164 #endif
165
166     RefPtr<EventDispatcher> eventDispatcher(this);
167     RunLoop::main().dispatch([eventDispatcher, pageID, wheelEvent] {
168         eventDispatcher->dispatchWheelEvent(pageID, wheelEvent);
169     }); 
170 }
171
172 #if ENABLE(IOS_TOUCH_EVENTS)
173 void EventDispatcher::clearQueuedTouchEventsForPage(const WebPage& webPage)
174 {
175     SpinLockHolder locker(&m_touchEventsLock);
176     m_touchEvents.remove(webPage.pageID());
177 }
178
179 void EventDispatcher::getQueuedTouchEventsForPage(const WebPage& webPage, TouchEventQueue& destinationQueue)
180 {
181     SpinLockHolder locker(&m_touchEventsLock);
182     destinationQueue = m_touchEvents.take(webPage.pageID());
183 }
184
185 void EventDispatcher::touchEvent(uint64_t pageID, const WebKit::WebTouchEvent& touchEvent)
186 {
187     bool updateListWasEmpty;
188     {
189         SpinLockHolder locker(&m_touchEventsLock);
190         updateListWasEmpty = m_touchEvents.isEmpty();
191         auto addResult = m_touchEvents.add(pageID, TouchEventQueue());
192         if (addResult.isNewEntry)
193             addResult.iterator->value.append(touchEvent);
194         else {
195             TouchEventQueue& queuedEvents = addResult.iterator->value;
196             ASSERT(!queuedEvents.isEmpty());
197             const WebTouchEvent& lastTouchEvent = queuedEvents.last();
198
199             // Coalesce touch move events.
200             WebEvent::Type type = lastTouchEvent.type();
201             if (type == WebEvent::TouchMove)
202                 queuedEvents.last() = touchEvent;
203             else
204                 queuedEvents.append(touchEvent);
205         }
206     }
207
208     if (updateListWasEmpty) {
209         RefPtr<EventDispatcher> eventDispatcher(this);
210         RunLoop::main().dispatch([eventDispatcher] {
211             eventDispatcher->dispatchTouchEvents();
212         });
213     }
214 }
215
216 void EventDispatcher::dispatchTouchEvents()
217 {
218     HashMap<uint64_t, TouchEventQueue> localCopy;
219     {
220         SpinLockHolder locker(&m_touchEventsLock);
221         localCopy.swap(m_touchEvents);
222     }
223
224     for (auto& slot : localCopy) {
225         if (WebPage* webPage = WebProcess::singleton().webPage(slot.key))
226             webPage->dispatchAsynchronousTouchEvents(slot.value);
227     }
228 }
229 #endif
230
231 void EventDispatcher::dispatchWheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent)
232 {
233     ASSERT(RunLoop::isMain());
234
235     WebPage* webPage = WebProcess::singleton().webPage(pageID);
236     if (!webPage)
237         return;
238
239     webPage->wheelEvent(wheelEvent);
240 }
241
242 #if ENABLE(ASYNC_SCROLLING)
243 void EventDispatcher::sendDidReceiveEvent(uint64_t pageID, const WebEvent& event, bool didHandleEvent)
244 {
245     WebProcess::singleton().parentProcessConnection()->send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(event.type()), didHandleEvent), pageID);
246 }
247 #endif
248
249 } // namespace WebKit