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
46namespace WebKit {
47using namespace WebCore;
48
49Ref<EventDispatcher> EventDispatcher::create()
50{
51 return adoptRef(*new EventDispatcher);
52}
53
54EventDispatcher::EventDispatcher()
55 : m_queue(WorkQueue::create("com.apple.WebKit.EventDispatcher", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive))
56 , m_recentWheelEventDeltaFilter(WheelEventDeltaFilter::create())
57{
58}
59
60EventDispatcher::~EventDispatcher()
61{
62}
63
64#if ENABLE(ASYNC_SCROLLING)
65void EventDispatcher::addScrollingTreeForPage(WebPage* webPage)
66{
67 LockHolder 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
76void EventDispatcher::removeScrollingTreeForPage(WebPage* webPage)
77{
78 LockHolder locker(m_scrollingTreesMutex);
79 ASSERT(m_scrollingTrees.contains(webPage->pageID()));
80
81 m_scrollingTrees.remove(webPage->pageID());
82}
83#endif
84
85void EventDispatcher::initializeConnection(IPC::Connection* connection)
86{
87 connection->addWorkQueueMessageReceiver(Messages::EventDispatcher::messageReceiverName(), m_queue.get(), this);
88}
89
90void EventDispatcher::wheelEvent(PageIdentifier pageID, const WebWheelEvent& wheelEvent, bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom)
91{
92#if PLATFORM(COCOA) || ENABLE(ASYNC_SCROLLING)
93 PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
94#endif
95
96#if PLATFORM(COCOA)
97 switch (wheelEvent.phase()) {
98 case WebWheelEvent::PhaseBegan:
99 m_recentWheelEventDeltaFilter->beginFilteringDeltas();
100 break;
101 case WebWheelEvent::PhaseEnded:
102 m_recentWheelEventDeltaFilter->endFilteringDeltas();
103 break;
104 default:
105 break;
106 }
107
108 if (m_recentWheelEventDeltaFilter->isFilteringDeltas()) {
109 m_recentWheelEventDeltaFilter->updateFromDelta(FloatSize(platformWheelEvent.deltaX(), platformWheelEvent.deltaY()));
110 FloatSize filteredDelta = m_recentWheelEventDeltaFilter->filteredDelta();
111 platformWheelEvent = platformWheelEvent.copyWithDeltasAndVelocity(filteredDelta.width(), filteredDelta.height(), m_recentWheelEventDeltaFilter->filteredVelocity());
112 }
113#endif
114
115#if ENABLE(ASYNC_SCROLLING)
116 LockHolder locker(m_scrollingTreesMutex);
117 if (RefPtr<ThreadedScrollingTree> scrollingTree = m_scrollingTrees.get(pageID)) {
118 // FIXME: It's pretty horrible that we're updating the back/forward state here.
119 // WebCore should always know the current state and know when it changes so the
120 // scrolling tree can be notified.
121 // We only need to do this at the beginning of the gesture.
122 if (platformWheelEvent.phase() == PlatformWheelEventPhaseBegan)
123 scrollingTree->setCanRubberBandState(canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom);
124
125 ScrollingEventResult result = scrollingTree->tryToHandleWheelEvent(platformWheelEvent);
126
127 if (result == ScrollingEventResult::DidHandleEvent || result == ScrollingEventResult::DidNotHandleEvent) {
128 sendDidReceiveEvent(pageID, wheelEvent, result == ScrollingEventResult::DidHandleEvent);
129 return;
130 }
131 }
132#else
133 UNUSED_PARAM(canRubberBandAtLeft);
134 UNUSED_PARAM(canRubberBandAtRight);
135 UNUSED_PARAM(canRubberBandAtTop);
136 UNUSED_PARAM(canRubberBandAtBottom);
137#endif
138
139 RunLoop::main().dispatch([protectedThis = makeRef(*this), pageID, wheelEvent]() mutable {
140 protectedThis->dispatchWheelEvent(pageID, wheelEvent);
141 });
142}
143
144#if ENABLE(MAC_GESTURE_EVENTS)
145void EventDispatcher::gestureEvent(PageIdentifier pageID, const WebKit::WebGestureEvent& gestureEvent)
146{
147 RunLoop::main().dispatch([protectedThis = makeRef(*this), pageID, gestureEvent]() mutable {
148 protectedThis->dispatchGestureEvent(pageID, gestureEvent);
149 });
150}
151#endif
152
153#if ENABLE(IOS_TOUCH_EVENTS)
154void EventDispatcher::clearQueuedTouchEventsForPage(const WebPage& webPage)
155{
156 LockHolder locker(&m_touchEventsLock);
157 m_touchEvents.remove(webPage.pageID());
158}
159
160void EventDispatcher::getQueuedTouchEventsForPage(const WebPage& webPage, TouchEventQueue& destinationQueue)
161{
162 LockHolder locker(&m_touchEventsLock);
163 destinationQueue = m_touchEvents.take(webPage.pageID());
164}
165
166void EventDispatcher::touchEvent(PageIdentifier pageID, const WebKit::WebTouchEvent& touchEvent)
167{
168 bool updateListWasEmpty;
169 {
170 LockHolder locker(&m_touchEventsLock);
171 updateListWasEmpty = m_touchEvents.isEmpty();
172 auto addResult = m_touchEvents.add(pageID, TouchEventQueue());
173 if (addResult.isNewEntry)
174 addResult.iterator->value.append(touchEvent);
175 else {
176 TouchEventQueue& queuedEvents = addResult.iterator->value;
177 ASSERT(!queuedEvents.isEmpty());
178 const WebTouchEvent& lastTouchEvent = queuedEvents.last();
179
180 // Coalesce touch move events.
181 if (touchEvent.type() == WebEvent::TouchMove && lastTouchEvent.type() == WebEvent::TouchMove)
182 queuedEvents.last() = touchEvent;
183 else
184 queuedEvents.append(touchEvent);
185 }
186 }
187
188 if (updateListWasEmpty) {
189 RunLoop::main().dispatch([protectedThis = makeRef(*this)]() mutable {
190 protectedThis->dispatchTouchEvents();
191 });
192 }
193}
194
195void EventDispatcher::dispatchTouchEvents()
196{
197 HashMap<PageIdentifier, TouchEventQueue> localCopy;
198 {
199 LockHolder locker(&m_touchEventsLock);
200 localCopy.swap(m_touchEvents);
201 }
202
203 for (auto& slot : localCopy) {
204 if (WebPage* webPage = WebProcess::singleton().webPage(slot.key))
205 webPage->dispatchAsynchronousTouchEvents(slot.value);
206 }
207}
208#endif
209
210void EventDispatcher::dispatchWheelEvent(PageIdentifier pageID, const WebWheelEvent& wheelEvent)
211{
212 ASSERT(RunLoop::isMain());
213
214 WebPage* webPage = WebProcess::singleton().webPage(pageID);
215 if (!webPage)
216 return;
217
218 webPage->wheelEvent(wheelEvent);
219}
220
221#if ENABLE(MAC_GESTURE_EVENTS)
222void EventDispatcher::dispatchGestureEvent(PageIdentifier pageID, const WebGestureEvent& gestureEvent)
223{
224 ASSERT(RunLoop::isMain());
225
226 WebPage* webPage = WebProcess::singleton().webPage(pageID);
227 if (!webPage)
228 return;
229
230 webPage->gestureEvent(gestureEvent);
231}
232#endif
233
234#if ENABLE(ASYNC_SCROLLING)
235void EventDispatcher::sendDidReceiveEvent(PageIdentifier pageID, const WebEvent& event, bool didHandleEvent)
236{
237 WebProcess::singleton().parentProcessConnection()->send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(event.type()), didHandleEvent), pageID);
238}
239#endif
240
241} // namespace WebKit
242