Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 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 "content/renderer/gpu/input_handler_proxy.h" | |
| 6 | |
| 7 #include "base/debug/trace_event.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "content/renderer/gpu/input_handler_proxy_client.h" | |
| 10 #include "third_party/WebKit/Source/Platform/chromium/public/Platform.h" | |
| 11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | |
| 12 | |
| 13 using WebKit::WebFloatPoint; | |
| 14 using WebKit::WebFloatSize; | |
| 15 using WebKit::WebGestureEvent; | |
| 16 using WebKit::WebInputEvent; | |
| 17 using WebKit::WebMouseWheelEvent; | |
| 18 using WebKit::WebPoint; | |
| 19 using WebKit::WebScrollbar; | |
| 20 using WebKit::WebTouchEvent; | |
| 21 | |
| 22 namespace content { | |
| 23 | |
| 24 InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler) | |
| 25 : client_(NULL), | |
| 26 input_handler_(input_handler), | |
| 27 #ifndef NDEBUG | |
| 28 expect_scroll_update_end_(false), | |
| 29 expect_pinch_update_end_(false), | |
| 30 #endif | |
| 31 gesture_scroll_on_impl_thread_(false), | |
| 32 gesture_pinch_on_impl_thread_(false), | |
| 33 fling_may_be_active_on_main_thread_(false) { | |
| 34 input_handler_->BindToClient(this); | |
| 35 } | |
| 36 | |
| 37 InputHandlerProxy::~InputHandlerProxy() {} | |
| 38 | |
| 39 void InputHandlerProxy::WillShutdown() { | |
| 40 if (client_) | |
| 41 client_->WillShutdown(); | |
| 42 } | |
| 43 | |
| 44 void InputHandlerProxy::SetClient(InputHandlerProxyClient* client) { | |
| 45 DCHECK(!client_); | |
| 46 client_ = client; | |
| 47 } | |
| 48 | |
| 49 void InputHandlerProxy::HandleInputEvent(const WebInputEvent& event) { | |
| 50 DCHECK(client_); | |
|
piman
2013/05/15 21:51:03
Worth a DCHECK(input_handler_) here, since we rely
| |
| 51 | |
| 52 InputHandlerProxy::EventDisposition disposition = | |
| 53 HandleInputEventInternal(event); | |
| 54 switch (disposition) { | |
| 55 case DidHandle: | |
| 56 client_->DidHandleInputEvent(); | |
| 57 break; | |
| 58 case DidNotHandle: | |
| 59 client_->DidNotHandleInputEvent(true /* send_to_widget */); | |
| 60 break; | |
| 61 case DropEvent: | |
| 62 client_->DidNotHandleInputEvent(false /* send_to_widget */); | |
| 63 break; | |
| 64 } | |
| 65 if (event.modifiers & WebInputEvent::IsLastInputEventForCurrentVSync) { | |
| 66 input_handler_->DidReceiveLastInputEventForVSync( | |
| 67 base::TimeTicks::FromInternalValue(event.timeStampSeconds * | |
| 68 base::Time::kMicrosecondsPerSecond)); | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 InputHandlerProxy::EventDisposition | |
| 73 InputHandlerProxy::HandleInputEventInternal(const WebInputEvent& event) { | |
| 74 if (event.type == WebInputEvent::MouseWheel) { | |
| 75 const WebMouseWheelEvent& wheel_event = | |
| 76 *static_cast<const WebMouseWheelEvent*>(&event); | |
| 77 if (wheel_event.scrollByPage) { | |
| 78 // TODO(jamesr): We don't properly handle scroll by page in the compositor | |
| 79 // thread, to punt it to the main thread. http://crbug.com/236 | |
|
danakj
2013/05/15 19:21:51
s/to/so/ ?
danakj
2013/05/15 19:21:51
the bug number looks truncated?
| |
| 80 return DidNotHandle; | |
| 81 } | |
| 82 cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin( | |
| 83 gfx::Point(wheel_event.x, wheel_event.y), cc::InputHandler::Wheel); | |
| 84 switch (scroll_status) { | |
| 85 case cc::InputHandler::ScrollStarted: { | |
| 86 TRACE_EVENT_INSTANT2( | |
| 87 "renderer", | |
| 88 "InputHandlerProxy::handle_input wheel scroll", | |
| 89 TRACE_EVENT_SCOPE_THREAD, | |
| 90 "deltaX", | |
| 91 -wheel_event.deltaX, | |
| 92 "deltaY", | |
| 93 -wheel_event.deltaY); | |
| 94 bool did_scroll = input_handler_->ScrollBy( | |
| 95 gfx::Point(wheel_event.x, wheel_event.y), | |
| 96 gfx::Vector2dF(-wheel_event.deltaX, -wheel_event.deltaY)); | |
| 97 input_handler_->ScrollEnd(); | |
| 98 return did_scroll ? DidHandle : DropEvent; | |
| 99 } | |
| 100 case cc::InputHandler::ScrollIgnored: | |
| 101 // TODO(jamesr): This should be DropEvent, but in cases where we fail to | |
| 102 // properly sync scrollability it's safer to send the | |
| 103 // event to the main thread. Change back to DropEvent once we have | |
| 104 // synchronization bugs sorted out. | |
| 105 return DidNotHandle; | |
| 106 case cc::InputHandler::ScrollOnMainThread: | |
| 107 return DidNotHandle; | |
| 108 } | |
| 109 } else if (event.type == WebInputEvent::GestureScrollBegin) { | |
| 110 DCHECK(!gesture_scroll_on_impl_thread_); | |
| 111 #ifndef NDEBUG | |
| 112 DCHECK(!expect_scroll_update_end_); | |
| 113 expect_scroll_update_end_ = true; | |
| 114 #endif | |
| 115 const WebGestureEvent& gesture_event = | |
| 116 *static_cast<const WebGestureEvent*>(&event); | |
| 117 cc::InputHandler::ScrollStatus scroll_status = input_handler_->ScrollBegin( | |
| 118 gfx::Point(gesture_event.x, gesture_event.y), | |
| 119 cc::InputHandler::Gesture); | |
| 120 switch (scroll_status) { | |
| 121 case cc::InputHandler::ScrollStarted: | |
| 122 gesture_scroll_on_impl_thread_ = true; | |
| 123 return DidHandle; | |
| 124 case cc::InputHandler::ScrollOnMainThread: | |
| 125 return DidNotHandle; | |
| 126 case cc::InputHandler::ScrollIgnored: | |
| 127 return DropEvent; | |
| 128 } | |
| 129 } else if (event.type == WebInputEvent::GestureScrollUpdate) { | |
| 130 #ifndef NDEBUG | |
| 131 DCHECK(expect_scroll_update_end_); | |
| 132 #endif | |
| 133 | |
| 134 if (!gesture_scroll_on_impl_thread_ && !gesture_pinch_on_impl_thread_) | |
| 135 return DidNotHandle; | |
| 136 | |
| 137 const WebGestureEvent& gesture_event = | |
| 138 *static_cast<const WebGestureEvent*>(&event); | |
| 139 bool did_scroll = input_handler_->ScrollBy( | |
| 140 gfx::Point(gesture_event.x, gesture_event.y), | |
| 141 gfx::Vector2dF(-gesture_event.data.scrollUpdate.deltaX, | |
| 142 -gesture_event.data.scrollUpdate.deltaY)); | |
| 143 return did_scroll ? DidHandle : DropEvent; | |
| 144 } else if (event.type == WebInputEvent::GestureScrollEnd) { | |
| 145 #ifndef NDEBUG | |
| 146 DCHECK(expect_scroll_update_end_); | |
| 147 expect_scroll_update_end_ = false; | |
| 148 #endif | |
| 149 if (!gesture_scroll_on_impl_thread_) | |
| 150 return DidNotHandle; | |
| 151 | |
| 152 input_handler_->ScrollEnd(); | |
| 153 gesture_scroll_on_impl_thread_ = false; | |
| 154 return DidHandle; | |
| 155 } else if (event.type == WebInputEvent::GesturePinchBegin) { | |
| 156 #ifndef NDEBUG | |
| 157 DCHECK(!expect_pinch_update_end_); | |
| 158 expect_pinch_update_end_ = true; | |
| 159 #endif | |
| 160 input_handler_->PinchGestureBegin(); | |
| 161 gesture_pinch_on_impl_thread_ = true; | |
| 162 return DidHandle; | |
| 163 } else if (event.type == WebInputEvent::GesturePinchEnd) { | |
| 164 #ifndef NDEBUG | |
| 165 DCHECK(expect_pinch_update_end_); | |
| 166 expect_pinch_update_end_ = false; | |
| 167 #endif | |
| 168 gesture_pinch_on_impl_thread_ = false; | |
| 169 input_handler_->PinchGestureEnd(); | |
| 170 return DidHandle; | |
| 171 } else if (event.type == WebInputEvent::GesturePinchUpdate) { | |
| 172 #ifndef NDEBUG | |
| 173 DCHECK(expect_pinch_update_end_); | |
| 174 #endif | |
| 175 const WebGestureEvent& gesture_event = | |
| 176 *static_cast<const WebGestureEvent*>(&event); | |
| 177 input_handler_->PinchGestureUpdate( | |
| 178 gesture_event.data.pinchUpdate.scale, | |
| 179 gfx::Point(gesture_event.x, gesture_event.y)); | |
| 180 return DidHandle; | |
| 181 } else if (event.type == WebInputEvent::GestureFlingStart) { | |
| 182 const WebGestureEvent& gesture_event = | |
| 183 *static_cast<const WebGestureEvent*>(&event); | |
| 184 return HandleGestureFling(gesture_event); | |
| 185 } else if (event.type == WebInputEvent::GestureFlingCancel) { | |
| 186 if (CancelCurrentFling()) | |
| 187 return DidHandle; | |
| 188 else if (!fling_may_be_active_on_main_thread_) | |
| 189 return DropEvent; | |
| 190 } else if (event.type == WebInputEvent::TouchStart) { | |
| 191 const WebTouchEvent& touch_event = | |
| 192 *static_cast<const WebTouchEvent*>(&event); | |
| 193 if (!input_handler_->HaveTouchEventHandlersAt(touch_event.touches[0] | |
| 194 .position)) | |
| 195 return DropEvent; | |
| 196 } else if (WebInputEvent::isKeyboardEventType(event.type)) { | |
| 197 CancelCurrentFling(); | |
| 198 } | |
| 199 | |
| 200 return DidNotHandle; | |
| 201 } | |
| 202 | |
| 203 InputHandlerProxy::EventDisposition | |
| 204 InputHandlerProxy::HandleGestureFling( | |
| 205 const WebGestureEvent& gesture_event) { | |
| 206 cc::InputHandler::ScrollStatus scroll_status; | |
| 207 | |
| 208 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) { | |
| 209 scroll_status = input_handler_->ScrollBegin( | |
| 210 gfx::Point(gesture_event.x, gesture_event.y), | |
| 211 cc::InputHandler::NonBubblingGesture); | |
| 212 } else { | |
| 213 if (!gesture_scroll_on_impl_thread_) | |
| 214 scroll_status = cc::InputHandler::ScrollOnMainThread; | |
| 215 else | |
| 216 scroll_status = input_handler_->FlingScrollBegin(); | |
| 217 } | |
| 218 | |
| 219 #ifndef NDEBUG | |
| 220 expect_scroll_update_end_ = false; | |
| 221 #endif | |
| 222 | |
| 223 switch (scroll_status) { | |
| 224 case cc::InputHandler::ScrollStarted: { | |
| 225 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) | |
| 226 input_handler_->ScrollEnd(); | |
| 227 | |
| 228 fling_curve_.reset(client_->CreateFlingAnimationCurve( | |
| 229 gesture_event.sourceDevice, | |
| 230 WebFloatPoint(gesture_event.data.flingStart.velocityX, | |
| 231 gesture_event.data.flingStart.velocityY), | |
| 232 WebKit::WebSize())); | |
| 233 TRACE_EVENT_ASYNC_BEGIN0( | |
| 234 "renderer", | |
| 235 "InputHandlerProxy::HandleGestureFling::started", | |
| 236 this); | |
| 237 fling_parameters_.delta = | |
| 238 WebFloatPoint(gesture_event.data.flingStart.velocityX, | |
| 239 gesture_event.data.flingStart.velocityY); | |
| 240 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); | |
| 241 fling_parameters_.globalPoint = | |
| 242 WebPoint(gesture_event.globalX, gesture_event.globalY); | |
| 243 fling_parameters_.modifiers = gesture_event.modifiers; | |
| 244 fling_parameters_.sourceDevice = gesture_event.sourceDevice; | |
| 245 input_handler_->ScheduleAnimation(); | |
| 246 return DidHandle; | |
| 247 } | |
| 248 case cc::InputHandler::ScrollOnMainThread: { | |
| 249 TRACE_EVENT_INSTANT0("renderer", | |
| 250 "InputHandlerProxy::HandleGestureFling::" | |
| 251 "scroll_on_main_thread", | |
| 252 TRACE_EVENT_SCOPE_THREAD); | |
| 253 fling_may_be_active_on_main_thread_ = true; | |
| 254 return DidNotHandle; | |
| 255 } | |
| 256 case cc::InputHandler::ScrollIgnored: { | |
| 257 TRACE_EVENT_INSTANT0( | |
| 258 "renderer", | |
| 259 "InputHandlerProxy::HandleGestureFling::ignored", | |
| 260 TRACE_EVENT_SCOPE_THREAD); | |
| 261 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) { | |
| 262 // We still pass the curve to the main thread if there's nothing | |
| 263 // scrollable, in case something | |
| 264 // registers a handler before the curve is over. | |
| 265 return DidNotHandle; | |
| 266 } | |
| 267 return DropEvent; | |
| 268 } | |
| 269 } | |
| 270 return DidNotHandle; | |
| 271 } | |
| 272 | |
| 273 void InputHandlerProxy::Animate(base::TimeTicks time) { | |
| 274 if (!fling_curve_) | |
| 275 return; | |
| 276 | |
| 277 double monotonic_time_sec = (time - base::TimeTicks()).InSecondsF(); | |
| 278 if (!fling_parameters_.startTime) { | |
| 279 fling_parameters_.startTime = monotonic_time_sec; | |
| 280 input_handler_->ScheduleAnimation(); | |
| 281 return; | |
| 282 } | |
| 283 | |
| 284 if (fling_curve_->apply(monotonic_time_sec - fling_parameters_.startTime, | |
| 285 this)) { | |
| 286 input_handler_->ScheduleAnimation(); | |
| 287 } else { | |
| 288 TRACE_EVENT_INSTANT0("renderer", | |
| 289 "InputHandlerProxy::animate::flingOver", | |
| 290 TRACE_EVENT_SCOPE_THREAD); | |
| 291 CancelCurrentFling(); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 void InputHandlerProxy::MainThreadHasStoppedFlinging() { | |
| 296 fling_may_be_active_on_main_thread_ = false; | |
| 297 } | |
| 298 | |
| 299 bool InputHandlerProxy::CancelCurrentFling() { | |
| 300 bool had_fling_animation = fling_curve_; | |
| 301 if (had_fling_animation && | |
| 302 fling_parameters_.sourceDevice == WebGestureEvent::Touchscreen) { | |
| 303 input_handler_->ScrollEnd(); | |
| 304 TRACE_EVENT_ASYNC_END0( | |
| 305 "renderer", | |
| 306 "InputHandlerProxy::HandleGestureFling::started", | |
| 307 this); | |
| 308 } | |
| 309 | |
| 310 TRACE_EVENT_INSTANT1("renderer", | |
| 311 "InputHandlerProxy::CancelCurrentFling", | |
| 312 TRACE_EVENT_SCOPE_THREAD, | |
| 313 "had_fling_animation", | |
| 314 had_fling_animation); | |
| 315 fling_curve_.reset(); | |
| 316 gesture_scroll_on_impl_thread_ = false; | |
| 317 fling_parameters_ = WebKit::WebActiveWheelFlingParameters(); | |
| 318 return had_fling_animation; | |
| 319 } | |
| 320 | |
| 321 bool InputHandlerProxy::TouchpadFlingScroll( | |
| 322 const WebFloatSize& increment) { | |
| 323 WebMouseWheelEvent synthetic_wheel; | |
| 324 synthetic_wheel.type = WebInputEvent::MouseWheel; | |
| 325 synthetic_wheel.deltaX = increment.width; | |
| 326 synthetic_wheel.deltaY = increment.height; | |
| 327 synthetic_wheel.hasPreciseScrollingDeltas = true; | |
| 328 synthetic_wheel.x = fling_parameters_.point.x; | |
| 329 synthetic_wheel.y = fling_parameters_.point.y; | |
| 330 synthetic_wheel.globalX = fling_parameters_.globalPoint.x; | |
| 331 synthetic_wheel.globalY = fling_parameters_.globalPoint.y; | |
| 332 synthetic_wheel.modifiers = fling_parameters_.modifiers; | |
| 333 | |
| 334 InputHandlerProxy::EventDisposition disposition = | |
| 335 HandleInputEventInternal(synthetic_wheel); | |
| 336 switch (disposition) { | |
| 337 case DidHandle: | |
| 338 return true; | |
| 339 case DropEvent: | |
| 340 break; | |
| 341 case DidNotHandle: | |
| 342 TRACE_EVENT_INSTANT0("renderer", | |
| 343 "InputHandlerProxy::scrollBy::AbortFling", | |
| 344 TRACE_EVENT_SCOPE_THREAD); | |
| 345 // If we got a DidNotHandle, that means we need to deliver wheels on the | |
| 346 // main thread. | |
| 347 // In this case we need to schedule a commit and transfer the fling curve | |
| 348 // over to the main | |
|
danakj
2013/05/15 19:21:51
nit: awkward line wrapping in this comment
| |
| 349 // thread and run the rest of the wheels from there. | |
| 350 // This can happen when flinging a page that contains a scrollable subarea | |
| 351 // that we can't | |
| 352 // scroll on the thread if the fling starts outside the subarea but then | |
| 353 // is flung "under" the | |
| 354 // pointer. | |
| 355 client_->TransferActiveWheelFlingAnimation(fling_parameters_); | |
| 356 fling_may_be_active_on_main_thread_ = true; | |
| 357 CancelCurrentFling(); | |
| 358 break; | |
| 359 } | |
| 360 | |
| 361 return false; | |
| 362 } | |
| 363 | |
| 364 static gfx::Vector2dF ToClientScrollIncrement(const WebFloatSize& increment) { | |
| 365 return gfx::Vector2dF(-increment.width, -increment.height); | |
| 366 } | |
| 367 | |
| 368 void InputHandlerProxy::scrollBy(const WebFloatSize& increment) { | |
| 369 if (increment == WebFloatSize()) | |
| 370 return; | |
| 371 | |
| 372 TRACE_EVENT2("renderer", | |
| 373 "InputHandlerProxy::scrollBy", | |
| 374 "x", | |
| 375 increment.width, | |
| 376 "y", | |
| 377 increment.height); | |
| 378 | |
| 379 bool did_scroll = false; | |
| 380 | |
| 381 switch (fling_parameters_.sourceDevice) { | |
| 382 case WebGestureEvent::Touchpad: | |
| 383 did_scroll = TouchpadFlingScroll(increment); | |
| 384 break; | |
| 385 case WebGestureEvent::Touchscreen: | |
| 386 did_scroll = input_handler_->ScrollBy(fling_parameters_.point, | |
| 387 ToClientScrollIncrement(increment)); | |
| 388 break; | |
| 389 } | |
| 390 | |
| 391 if (did_scroll) { | |
| 392 fling_parameters_.cumulativeScroll.width += increment.width; | |
| 393 fling_parameters_.cumulativeScroll.height += increment.height; | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 void InputHandlerProxy::notifyCurrentFlingVelocity( | |
| 398 const WebFloatSize& velocity) { | |
| 399 TRACE_EVENT2("renderer", | |
| 400 "InputHandlerProxy::notifyCurrentFlingVelocity", | |
| 401 "vx", | |
| 402 velocity.width, | |
| 403 "vy", | |
| 404 velocity.height); | |
| 405 input_handler_->NotifyCurrentFlingVelocity(ToClientScrollIncrement(velocity)); | |
| 406 } | |
| 407 | |
| 408 } // namespace content | |
| OLD | NEW |