| OLD | NEW |
| (Empty) |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 | |
| 7 #include "WebCompositorInputHandlerImpl.h" | |
| 8 | |
| 9 #include "CCActiveGestureAnimation.h" | |
| 10 #include "CCProxy.h" | |
| 11 #include "PlatformGestureCurveTarget.h" | |
| 12 #include "TouchpadFlingPlatformGestureCurve.h" | |
| 13 #include "TraceEvent.h" | |
| 14 #include "WebCompositorImpl.h" | |
| 15 #include "WebCompositorInputHandlerClient.h" | |
| 16 #include "WebInputEvent.h" | |
| 17 #include <wtf/ThreadingPrimitives.h> | |
| 18 | |
| 19 using namespace WebCore; | |
| 20 | |
| 21 namespace WebCore { | |
| 22 | |
| 23 PassOwnPtr<CCInputHandler> CCInputHandler::create(CCInputHandlerClient* inputHan
dlerClient) | |
| 24 { | |
| 25 return WebKit::WebCompositorInputHandlerImpl::create(inputHandlerClient); | |
| 26 } | |
| 27 | |
| 28 class PlatformGestureToCCGestureAdapter : public CCGestureCurve, public Platform
GestureCurveTarget { | |
| 29 public: | |
| 30 static PassOwnPtr<CCGestureCurve> create(PassOwnPtr<PlatformGestureCurve> pl
atformCurve) | |
| 31 { | |
| 32 return adoptPtr(new PlatformGestureToCCGestureAdapter(platformCurve)); | |
| 33 } | |
| 34 | |
| 35 virtual const char* debugName() const | |
| 36 { | |
| 37 return m_curve->debugName(); | |
| 38 } | |
| 39 | |
| 40 virtual bool apply(double time, CCGestureCurveTarget* target) | |
| 41 { | |
| 42 ASSERT(target); | |
| 43 m_target = target; | |
| 44 return m_curve->apply(time, this); | |
| 45 } | |
| 46 | |
| 47 virtual void scrollBy(const IntPoint& scrollDelta) | |
| 48 { | |
| 49 ASSERT(m_target); | |
| 50 m_target->scrollBy(scrollDelta); | |
| 51 } | |
| 52 | |
| 53 private: | |
| 54 PlatformGestureToCCGestureAdapter(PassOwnPtr<PlatformGestureCurve> curve) | |
| 55 : m_curve(curve) | |
| 56 , m_target(0) | |
| 57 { | |
| 58 } | |
| 59 | |
| 60 OwnPtr<PlatformGestureCurve> m_curve; | |
| 61 CCGestureCurveTarget* m_target; | |
| 62 }; | |
| 63 | |
| 64 } | |
| 65 | |
| 66 namespace WebKit { | |
| 67 | |
| 68 // These statics may only be accessed from the compositor thread. | |
| 69 int WebCompositorInputHandlerImpl::s_nextAvailableIdentifier = 1; | |
| 70 HashSet<WebCompositorInputHandlerImpl*>* WebCompositorInputHandlerImpl::s_compos
itors = 0; | |
| 71 | |
| 72 WebCompositorInputHandler* WebCompositorInputHandler::fromIdentifier(int identif
ier) | |
| 73 { | |
| 74 return WebCompositorInputHandlerImpl::fromIdentifier(identifier); | |
| 75 } | |
| 76 | |
| 77 PassOwnPtr<WebCompositorInputHandlerImpl> WebCompositorInputHandlerImpl::create(
WebCore::CCInputHandlerClient* inputHandlerClient) | |
| 78 { | |
| 79 return adoptPtr(new WebCompositorInputHandlerImpl(inputHandlerClient)); | |
| 80 } | |
| 81 | |
| 82 WebCompositorInputHandler* WebCompositorInputHandlerImpl::fromIdentifier(int ide
ntifier) | |
| 83 { | |
| 84 ASSERT(WebCompositorImpl::initialized()); | |
| 85 ASSERT(CCProxy::isImplThread()); | |
| 86 | |
| 87 if (!s_compositors) | |
| 88 return 0; | |
| 89 | |
| 90 for (HashSet<WebCompositorInputHandlerImpl*>::iterator it = s_compositors->b
egin(); it != s_compositors->end(); ++it) { | |
| 91 if ((*it)->identifier() == identifier) | |
| 92 return *it; | |
| 93 } | |
| 94 return 0; | |
| 95 } | |
| 96 | |
| 97 WebCompositorInputHandlerImpl::WebCompositorInputHandlerImpl(CCInputHandlerClien
t* inputHandlerClient) | |
| 98 : m_client(0) | |
| 99 , m_identifier(s_nextAvailableIdentifier++) | |
| 100 , m_inputHandlerClient(inputHandlerClient) | |
| 101 #ifndef NDEBUG | |
| 102 , m_expectScrollUpdateEnd(false) | |
| 103 , m_expectPinchUpdateEnd(false) | |
| 104 #endif | |
| 105 , m_gestureScrollStarted(false) | |
| 106 { | |
| 107 ASSERT(CCProxy::isImplThread()); | |
| 108 | |
| 109 if (!s_compositors) | |
| 110 s_compositors = new HashSet<WebCompositorInputHandlerImpl*>; | |
| 111 s_compositors->add(this); | |
| 112 } | |
| 113 | |
| 114 WebCompositorInputHandlerImpl::~WebCompositorInputHandlerImpl() | |
| 115 { | |
| 116 ASSERT(CCProxy::isImplThread()); | |
| 117 if (m_client) | |
| 118 m_client->willShutdown(); | |
| 119 | |
| 120 ASSERT(s_compositors); | |
| 121 s_compositors->remove(this); | |
| 122 if (!s_compositors->size()) { | |
| 123 delete s_compositors; | |
| 124 s_compositors = 0; | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void WebCompositorInputHandlerImpl::setClient(WebCompositorInputHandlerClient* c
lient) | |
| 129 { | |
| 130 ASSERT(CCProxy::isImplThread()); | |
| 131 // It's valid to set a new client if we've never had one or to clear the cli
ent, but it's not valid to change from having one client to a different one. | |
| 132 ASSERT(!m_client || !client); | |
| 133 m_client = client; | |
| 134 } | |
| 135 | |
| 136 void WebCompositorInputHandlerImpl::handleInputEvent(const WebInputEvent& event) | |
| 137 { | |
| 138 ASSERT(CCProxy::isImplThread()); | |
| 139 ASSERT(m_client); | |
| 140 | |
| 141 WebCompositorInputHandlerImpl::EventDisposition disposition = handleInputEve
ntInternal(event); | |
| 142 switch (disposition) { | |
| 143 case DidHandle: | |
| 144 m_client->didHandleInputEvent(); | |
| 145 break; | |
| 146 case DidNotHandle: | |
| 147 m_client->didNotHandleInputEvent(true /* sendToWidget */); | |
| 148 break; | |
| 149 case DropEvent: | |
| 150 m_client->didNotHandleInputEvent(false /* sendToWidget */); | |
| 151 break; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 WebCompositorInputHandlerImpl::EventDisposition WebCompositorInputHandlerImpl::h
andleInputEventInternal(const WebInputEvent& event) | |
| 156 { | |
| 157 if (event.type == WebInputEvent::MouseWheel) { | |
| 158 const WebMouseWheelEvent& wheelEvent = *static_cast<const WebMouseWheelE
vent*>(&event); | |
| 159 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->
scrollBegin(IntPoint(wheelEvent.x, wheelEvent.y), CCInputHandlerClient::Wheel); | |
| 160 switch (scrollStatus) { | |
| 161 case CCInputHandlerClient::ScrollStarted: { | |
| 162 TRACE_EVENT_INSTANT2("cc", "WebCompositorInputHandlerImpl::handleInp
ut wheel scroll", "deltaX", -wheelEvent.deltaX, "deltaY", -wheelEvent.deltaY); | |
| 163 m_inputHandlerClient->scrollBy(IntPoint(wheelEvent.x, wheelEvent.y),
IntSize(-wheelEvent.deltaX, -wheelEvent.deltaY)); | |
| 164 m_inputHandlerClient->scrollEnd(); | |
| 165 return DidHandle; | |
| 166 } | |
| 167 case CCInputHandlerClient::ScrollIgnored: | |
| 168 // FIXME: This should be DropEvent, but in cases where we fail to pr
operly sync scrollability it's safer to send the | |
| 169 // event to the main thread. Change back to DropEvent once we have s
ynchronization bugs sorted out. | |
| 170 return DidNotHandle; | |
| 171 case CCInputHandlerClient::ScrollOnMainThread: | |
| 172 return DidNotHandle; | |
| 173 } | |
| 174 } else if (event.type == WebInputEvent::GestureScrollBegin) { | |
| 175 ASSERT(!m_gestureScrollStarted); | |
| 176 ASSERT(!m_expectScrollUpdateEnd); | |
| 177 #ifndef NDEBUG | |
| 178 m_expectScrollUpdateEnd = true; | |
| 179 #endif | |
| 180 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
| 181 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->
scrollBegin(IntPoint(gestureEvent.x, gestureEvent.y), CCInputHandlerClient::Gest
ure); | |
| 182 switch (scrollStatus) { | |
| 183 case CCInputHandlerClient::ScrollStarted: | |
| 184 m_gestureScrollStarted = true; | |
| 185 return DidHandle; | |
| 186 case CCInputHandlerClient::ScrollOnMainThread: | |
| 187 return DidNotHandle; | |
| 188 case CCInputHandlerClient::ScrollIgnored: | |
| 189 return DropEvent; | |
| 190 } | |
| 191 } else if (event.type == WebInputEvent::GestureScrollUpdate) { | |
| 192 ASSERT(m_expectScrollUpdateEnd); | |
| 193 | |
| 194 if (!m_gestureScrollStarted) | |
| 195 return DidNotHandle; | |
| 196 | |
| 197 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
| 198 m_inputHandlerClient->scrollBy(IntPoint(gestureEvent.x, gestureEvent.y),
IntSize(-gestureEvent.deltaX, -gestureEvent.deltaY)); | |
| 199 return DidHandle; | |
| 200 } else if (event.type == WebInputEvent::GestureScrollEnd) { | |
| 201 ASSERT(m_expectScrollUpdateEnd); | |
| 202 #ifndef NDEBUG | |
| 203 m_expectScrollUpdateEnd = false; | |
| 204 #endif | |
| 205 if (!m_gestureScrollStarted) | |
| 206 return DidNotHandle; | |
| 207 | |
| 208 m_inputHandlerClient->scrollEnd(); | |
| 209 m_gestureScrollStarted = false; | |
| 210 return DidHandle; | |
| 211 } else if (event.type == WebInputEvent::GesturePinchBegin) { | |
| 212 ASSERT(!m_expectPinchUpdateEnd); | |
| 213 #ifndef NDEBUG | |
| 214 m_expectPinchUpdateEnd = true; | |
| 215 #endif | |
| 216 m_inputHandlerClient->pinchGestureBegin(); | |
| 217 return DidHandle; | |
| 218 } else if (event.type == WebInputEvent::GesturePinchEnd) { | |
| 219 ASSERT(m_expectPinchUpdateEnd); | |
| 220 #ifndef NDEBUG | |
| 221 m_expectPinchUpdateEnd = false; | |
| 222 #endif | |
| 223 m_inputHandlerClient->pinchGestureEnd(); | |
| 224 return DidHandle; | |
| 225 } else if (event.type == WebInputEvent::GesturePinchUpdate) { | |
| 226 ASSERT(m_expectPinchUpdateEnd); | |
| 227 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
| 228 m_inputHandlerClient->pinchGestureUpdate(gestureEvent.deltaX, IntPoint(g
estureEvent.x, gestureEvent.y)); | |
| 229 return DidHandle; | |
| 230 } else if (event.type == WebInputEvent::GestureFlingStart) { | |
| 231 const WebGestureEvent& gestureEvent = *static_cast<const WebGestureEvent
*>(&event); | |
| 232 return handleGestureFling(gestureEvent); | |
| 233 } else if (event.type == WebInputEvent::GestureFlingCancel) { | |
| 234 if (cancelCurrentFling()) | |
| 235 return DidHandle; | |
| 236 } else if (WebInputEvent::isKeyboardEventType(event.type)) { | |
| 237 cancelCurrentFling(); | |
| 238 } | |
| 239 | |
| 240 return DidNotHandle; | |
| 241 } | |
| 242 | |
| 243 WebCompositorInputHandlerImpl::EventDisposition WebCompositorInputHandlerImpl::h
andleGestureFling(const WebGestureEvent& gestureEvent) | |
| 244 { | |
| 245 CCInputHandlerClient::ScrollStatus scrollStatus = m_inputHandlerClient->scro
llBegin(IntPoint(gestureEvent.x, gestureEvent.y), CCInputHandlerClient::Gesture)
; | |
| 246 switch (scrollStatus) { | |
| 247 case CCInputHandlerClient::ScrollStarted: { | |
| 248 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::started"); | |
| 249 OwnPtr<PlatformGestureCurve> flingCurve = TouchpadFlingPlatformGestureCu
rve::create(FloatPoint(gestureEvent.deltaX, gestureEvent.deltaY)); | |
| 250 m_wheelFlingAnimation = CCActiveGestureAnimation::create(PlatformGesture
ToCCGestureAdapter::create(flingCurve.release()), this); | |
| 251 m_wheelFlingParameters.delta = WebFloatPoint(gestureEvent.deltaX, gestur
eEvent.deltaY); | |
| 252 m_wheelFlingParameters.point = WebPoint(gestureEvent.x, gestureEvent.y); | |
| 253 m_wheelFlingParameters.globalPoint = WebPoint(gestureEvent.globalX, gest
ureEvent.globalY); | |
| 254 m_wheelFlingParameters.modifiers = gestureEvent.modifiers; | |
| 255 m_inputHandlerClient->scheduleAnimation(); | |
| 256 return DidHandle; | |
| 257 } | |
| 258 case CCInputHandlerClient::ScrollOnMainThread: { | |
| 259 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::scrollOnMainThread"); | |
| 260 return DidNotHandle; | |
| 261 } | |
| 262 case CCInputHandlerClient::ScrollIgnored: { | |
| 263 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::handleGesture
Fling::ignored"); | |
| 264 // We still pass the curve to the main thread if there's nothing scrolla
ble, in case something | |
| 265 // registers a handler before the curve is over. | |
| 266 return DidNotHandle; | |
| 267 } | |
| 268 } | |
| 269 return DidNotHandle; | |
| 270 } | |
| 271 | |
| 272 int WebCompositorInputHandlerImpl::identifier() const | |
| 273 { | |
| 274 ASSERT(CCProxy::isImplThread()); | |
| 275 return m_identifier; | |
| 276 } | |
| 277 | |
| 278 void WebCompositorInputHandlerImpl::animate(double monotonicTime) | |
| 279 { | |
| 280 if (!m_wheelFlingAnimation) | |
| 281 return; | |
| 282 | |
| 283 if (!m_wheelFlingParameters.startTime) | |
| 284 m_wheelFlingParameters.startTime = monotonicTime; | |
| 285 | |
| 286 if (m_wheelFlingAnimation->animate(monotonicTime)) | |
| 287 m_inputHandlerClient->scheduleAnimation(); | |
| 288 else { | |
| 289 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::animate::flin
gOver"); | |
| 290 cancelCurrentFling(); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 bool WebCompositorInputHandlerImpl::cancelCurrentFling() | |
| 295 { | |
| 296 bool hadFlingAnimation = m_wheelFlingAnimation; | |
| 297 TRACE_EVENT_INSTANT1("cc", "WebCompositorInputHandlerImpl::cancelCurrentFlin
g", "hadFlingAnimation", hadFlingAnimation); | |
| 298 m_wheelFlingAnimation.clear(); | |
| 299 m_wheelFlingParameters = WebActiveWheelFlingParameters(); | |
| 300 return hadFlingAnimation; | |
| 301 } | |
| 302 | |
| 303 void WebCompositorInputHandlerImpl::scrollBy(const IntPoint& increment) | |
| 304 { | |
| 305 if (increment == IntPoint::zero()) | |
| 306 return; | |
| 307 | |
| 308 TRACE_EVENT2("cc", "WebCompositorInputHandlerImpl::scrollBy", "x", increment
.x(), "y", increment.y()); | |
| 309 WebMouseWheelEvent syntheticWheel; | |
| 310 syntheticWheel.type = WebInputEvent::MouseWheel; | |
| 311 syntheticWheel.deltaX = increment.x(); | |
| 312 syntheticWheel.deltaY = increment.y(); | |
| 313 syntheticWheel.hasPreciseScrollingDeltas = true; | |
| 314 syntheticWheel.x = m_wheelFlingParameters.point.x; | |
| 315 syntheticWheel.y = m_wheelFlingParameters.point.y; | |
| 316 syntheticWheel.globalX = m_wheelFlingParameters.globalPoint.x; | |
| 317 syntheticWheel.globalY = m_wheelFlingParameters.globalPoint.y; | |
| 318 syntheticWheel.modifiers = m_wheelFlingParameters.modifiers; | |
| 319 | |
| 320 WebCompositorInputHandlerImpl::EventDisposition disposition = handleInputEve
ntInternal(syntheticWheel); | |
| 321 switch (disposition) { | |
| 322 case DidHandle: | |
| 323 m_wheelFlingParameters.cumulativeScroll.width += increment.x(); | |
| 324 m_wheelFlingParameters.cumulativeScroll.height += increment.y(); | |
| 325 case DropEvent: | |
| 326 break; | |
| 327 case DidNotHandle: | |
| 328 TRACE_EVENT_INSTANT0("cc", "WebCompositorInputHandlerImpl::scrollBy::Abo
rtFling"); | |
| 329 // If we got a DidNotHandle, that means we need to deliver wheels on the
main thread. | |
| 330 // In this case we need to schedule a commit and transfer the fling curv
e over to the main | |
| 331 // thread and run the rest of the wheels from there. | |
| 332 // This can happen when flinging a page that contains a scrollable subar
ea that we can't | |
| 333 // scroll on the thread if the fling starts outside the subarea but then
is flung "under" the | |
| 334 // pointer. | |
| 335 m_client->transferActiveWheelFlingAnimation(m_wheelFlingParameters); | |
| 336 cancelCurrentFling(); | |
| 337 break; | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 } | |
| OLD | NEW |