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 45using namespace WebCore; 46 47namespace WebKit { 48 49PassRefPtr<EventDispatcher> EventDispatcher::create() 50{ 51 return adoptRef(new EventDispatcher); 52} 53 54EventDispatcher::EventDispatcher() 55 : m_queue(WorkQueue::create("com.apple.WebKit.EventDispatcher", WorkQueue::QOS::UserInteractive)) 56 , m_recentWheelEventDeltaTracker(std::make_unique<WheelEventDeltaTracker>()) 57#if ENABLE(IOS_TOUCH_EVENTS) 58 , m_touchEventsLock(SPINLOCK_INITIALIZER) 59#endif 60{ 61} 62 63EventDispatcher::~EventDispatcher() 64{ 65} 66 67#if ENABLE(ASYNC_SCROLLING) 68void EventDispatcher::addScrollingTreeForPage(WebPage* webPage) 69{ 70 MutexLocker locker(m_scrollingTreesMutex); 71 72 ASSERT(webPage->corePage()->scrollingCoordinator()); 73 ASSERT(!m_scrollingTrees.contains(webPage->pageID())); 74 75 AsyncScrollingCoordinator* scrollingCoordinator = toAsyncScrollingCoordinator(webPage->corePage()->scrollingCoordinator()); 76 m_scrollingTrees.set(webPage->pageID(), toThreadedScrollingTree(scrollingCoordinator->scrollingTree())); 77} 78 79void EventDispatcher::removeScrollingTreeForPage(WebPage* webPage) 80{ 81 MutexLocker locker(m_scrollingTreesMutex); 82 ASSERT(m_scrollingTrees.contains(webPage->pageID())); 83 84 m_scrollingTrees.remove(webPage->pageID()); 85} 86#endif 87 88void EventDispatcher::initializeConnection(IPC::Connection* connection) 89{ 90 connection->addWorkQueueMessageReceiver(Messages::EventDispatcher::messageReceiverName(), m_queue.get(), this); 91} 92 93void EventDispatcher::wheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent, bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom) 94{ 95 PlatformWheelEvent platformWheelEvent = platform(wheelEvent); 96 97#if PLATFORM(COCOA) 98 switch (wheelEvent.phase()) { 99 case PlatformWheelEventPhaseBegan: 100 m_recentWheelEventDeltaTracker->beginTrackingDeltas(); 101 break; 102 case PlatformWheelEventPhaseEnded: 103 m_recentWheelEventDeltaTracker->endTrackingDeltas(); 104 break; 105 default: 106 break; 107 } 108 109 if (m_recentWheelEventDeltaTracker->isTrackingDeltas()) { 110 m_recentWheelEventDeltaTracker->recordWheelEventDelta(platformWheelEvent); 111 112 DominantScrollGestureDirection dominantDirection = DominantScrollGestureDirection::None; 113 dominantDirection = m_recentWheelEventDeltaTracker->dominantScrollGestureDirection(); 114 115 // Workaround for scrolling issues <rdar://problem/14758615>. 116 if (dominantDirection == DominantScrollGestureDirection::Vertical && platformWheelEvent.deltaX()) 117 platformWheelEvent = platformWheelEvent.copyIgnoringHorizontalDelta(); 118 else if (dominantDirection == DominantScrollGestureDirection::Horizontal && platformWheelEvent.deltaY()) 119 platformWheelEvent = platformWheelEvent.copyIgnoringVerticalDelta(); 120 } 121#endif 122 123#if ENABLE(ASYNC_SCROLLING) 124 MutexLocker locker(m_scrollingTreesMutex); 125 if (ThreadedScrollingTree* scrollingTree = m_scrollingTrees.get(pageID)) { 126 // FIXME: It's pretty horrible that we're updating the back/forward state here. 127 // WebCore should always know the current state and know when it changes so the 128 // scrolling tree can be notified. 129 // We only need to do this at the beginning of the gesture. 130 if (platformWheelEvent.phase() == PlatformWheelEventPhaseBegan) 131 ScrollingThread::dispatch(bind(&ThreadedScrollingTree::setCanRubberBandState, scrollingTree, canRubberBandAtLeft, canRubberBandAtRight, canRubberBandAtTop, canRubberBandAtBottom)); 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 RunLoop::main().dispatch(bind(&EventDispatcher::dispatchWheelEvent, this, pageID, wheelEvent)); 147} 148 149#if ENABLE(IOS_TOUCH_EVENTS) 150void EventDispatcher::clearQueuedTouchEventsForPage(const WebPage& webPage) 151{ 152 SpinLockHolder locker(&m_touchEventsLock); 153 m_touchEvents.remove(webPage.pageID()); 154} 155 156void EventDispatcher::getQueuedTouchEventsForPage(const WebPage& webPage, TouchEventQueue& destinationQueue) 157{ 158 SpinLockHolder locker(&m_touchEventsLock); 159 destinationQueue = m_touchEvents.take(webPage.pageID()); 160} 161 162void EventDispatcher::touchEvent(uint64_t pageID, const WebKit::WebTouchEvent& touchEvent) 163{ 164 bool updateListWasEmpty; 165 { 166 SpinLockHolder locker(&m_touchEventsLock); 167 updateListWasEmpty = m_touchEvents.isEmpty(); 168 auto addResult = m_touchEvents.add(pageID, TouchEventQueue()); 169 if (addResult.isNewEntry) 170 addResult.iterator->value.append(touchEvent); 171 else { 172 TouchEventQueue& queuedEvents = addResult.iterator->value; 173 ASSERT(!queuedEvents.isEmpty()); 174 const WebTouchEvent& lastTouchEvent = queuedEvents.last(); 175 176 // Coalesce touch move events. 177 WebEvent::Type type = lastTouchEvent.type(); 178 if (type == WebEvent::TouchMove) 179 queuedEvents.last() = touchEvent; 180 else 181 queuedEvents.append(touchEvent); 182 } 183 } 184 185 if (updateListWasEmpty) 186 RunLoop::main().dispatch(bind(&EventDispatcher::dispatchTouchEvents, this)); 187} 188 189void EventDispatcher::dispatchTouchEvents() 190{ 191 HashMap<uint64_t, TouchEventQueue> localCopy; 192 { 193 SpinLockHolder locker(&m_touchEventsLock); 194 localCopy.swap(m_touchEvents); 195 } 196 197 for (auto& slot : localCopy) { 198 if (WebPage* webPage = WebProcess::shared().webPage(slot.key)) 199 webPage->dispatchAsynchronousTouchEvents(slot.value); 200 } 201} 202#endif 203 204void EventDispatcher::dispatchWheelEvent(uint64_t pageID, const WebWheelEvent& wheelEvent) 205{ 206 ASSERT(RunLoop::isMain()); 207 208 WebPage* webPage = WebProcess::shared().webPage(pageID); 209 if (!webPage) 210 return; 211 212 webPage->wheelEvent(wheelEvent); 213} 214 215#if ENABLE(ASYNC_SCROLLING) 216void EventDispatcher::sendDidReceiveEvent(uint64_t pageID, const WebEvent& event, bool didHandleEvent) 217{ 218 WebProcess::shared().parentProcessConnection()->send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(event.type()), didHandleEvent), pageID); 219} 220#endif 221 222} // namespace WebKit 223