| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/gpu/input_handler_proxy.h" | 5 #include "content/renderer/gpu/input_handler_proxy.h" |
| 6 | 6 |
| 7 #include "base/debug/trace_event.h" | 7 #include "base/debug/trace_event.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "content/renderer/gpu/input_handler_proxy_client.h" | 10 #include "content/renderer/gpu/input_handler_proxy_client.h" |
| 11 #include "third_party/WebKit/public/platform/Platform.h" | 11 #include "third_party/WebKit/public/platform/WebFloatSize.h" |
| 12 #include "third_party/WebKit/public/web/WebInputEvent.h" | 12 #include "third_party/WebKit/public/web/WebInputEvent.h" |
| 13 #include "ui/events/latency_info.h" | 13 #include "ui/events/latency_info.h" |
| 14 | 14 |
| 15 using WebKit::WebFloatPoint; | 15 using WebKit::WebFloatPoint; |
| 16 using WebKit::WebFloatSize; | 16 using WebKit::WebFloatSize; |
| 17 using WebKit::WebGestureEvent; | 17 using WebKit::WebGestureEvent; |
| 18 using WebKit::WebInputEvent; | 18 using WebKit::WebInputEvent; |
| 19 using WebKit::WebMouseEvent; | 19 using WebKit::WebMouseEvent; |
| 20 using WebKit::WebMouseWheelEvent; | 20 using WebKit::WebMouseWheelEvent; |
| 21 using WebKit::WebPoint; | 21 using WebKit::WebPoint; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 namespace content { | 53 namespace content { |
| 54 | 54 |
| 55 InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler) | 55 InputHandlerProxy::InputHandlerProxy(cc::InputHandler* input_handler) |
| 56 : client_(NULL), | 56 : client_(NULL), |
| 57 input_handler_(input_handler), | 57 input_handler_(input_handler), |
| 58 #ifndef NDEBUG | 58 #ifndef NDEBUG |
| 59 expect_scroll_update_end_(false), | 59 expect_scroll_update_end_(false), |
| 60 expect_pinch_update_end_(false), | 60 expect_pinch_update_end_(false), |
| 61 #endif | 61 #endif |
| 62 gesture_scroll_on_impl_thread_(false), | 62 gesture_scroll_on_impl_thread_(false), |
| 63 gesture_pinch_on_impl_thread_(false), | 63 gesture_pinch_on_impl_thread_(false) { |
| 64 fling_may_be_active_on_main_thread_(false), | |
| 65 fling_overscrolled_horizontally_(false), | |
| 66 fling_overscrolled_vertically_(false) { | |
| 67 input_handler_->BindToClient(this); | 64 input_handler_->BindToClient(this); |
| 68 } | 65 } |
| 69 | 66 |
| 70 InputHandlerProxy::~InputHandlerProxy() {} | 67 InputHandlerProxy::~InputHandlerProxy() {} |
| 71 | 68 |
| 72 void InputHandlerProxy::WillShutdown() { | 69 void InputHandlerProxy::WillShutdown() { |
| 73 input_handler_ = NULL; | 70 input_handler_ = NULL; |
| 74 DCHECK(client_); | 71 DCHECK(client_); |
| 75 client_->WillShutdown(); | 72 client_->WillShutdown(); |
| 76 } | 73 } |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 #ifndef NDEBUG | 198 #ifndef NDEBUG |
| 202 DCHECK(expect_pinch_update_end_); | 199 DCHECK(expect_pinch_update_end_); |
| 203 #endif | 200 #endif |
| 204 const WebGestureEvent& gesture_event = | 201 const WebGestureEvent& gesture_event = |
| 205 *static_cast<const WebGestureEvent*>(&event); | 202 *static_cast<const WebGestureEvent*>(&event); |
| 206 input_handler_->PinchGestureUpdate( | 203 input_handler_->PinchGestureUpdate( |
| 207 gesture_event.data.pinchUpdate.scale, | 204 gesture_event.data.pinchUpdate.scale, |
| 208 gfx::Point(gesture_event.x, gesture_event.y)); | 205 gfx::Point(gesture_event.x, gesture_event.y)); |
| 209 return DID_HANDLE; | 206 return DID_HANDLE; |
| 210 } else if (event.type == WebInputEvent::GestureFlingStart) { | 207 } else if (event.type == WebInputEvent::GestureFlingStart) { |
| 211 const WebGestureEvent& gesture_event = | 208 NOTREACHED(); |
| 212 *static_cast<const WebGestureEvent*>(&event); | |
| 213 return HandleGestureFling(gesture_event); | |
| 214 } else if (event.type == WebInputEvent::GestureFlingCancel) { | 209 } else if (event.type == WebInputEvent::GestureFlingCancel) { |
| 215 if (CancelCurrentFling()) | 210 NOTREACHED(); |
| 216 return DID_HANDLE; | |
| 217 else if (!fling_may_be_active_on_main_thread_) | |
| 218 return DROP_EVENT; | |
| 219 } else if (event.type == WebInputEvent::TouchStart) { | 211 } else if (event.type == WebInputEvent::TouchStart) { |
| 220 const WebTouchEvent& touch_event = | 212 const WebTouchEvent& touch_event = |
| 221 *static_cast<const WebTouchEvent*>(&event); | 213 *static_cast<const WebTouchEvent*>(&event); |
| 222 if (!input_handler_->HaveTouchEventHandlersAt(touch_event.touches[0] | 214 if (!input_handler_->HaveTouchEventHandlersAt(touch_event.touches[0] |
| 223 .position)) | 215 .position)) |
| 224 return DROP_EVENT; | 216 return DROP_EVENT; |
| 225 } else if (WebInputEvent::isKeyboardEventType(event.type)) { | |
| 226 CancelCurrentFling(); | |
| 227 } else if (event.type == WebInputEvent::MouseMove) { | 217 } else if (event.type == WebInputEvent::MouseMove) { |
| 228 const WebMouseEvent& mouse_event = | 218 const WebMouseEvent& mouse_event = |
| 229 *static_cast<const WebMouseEvent*>(&event); | 219 *static_cast<const WebMouseEvent*>(&event); |
| 230 // TODO(tony): Ignore when mouse buttons are down? | 220 // TODO(tony): Ignore when mouse buttons are down? |
| 231 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); | 221 input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y)); |
| 232 } | 222 } |
| 233 | 223 |
| 234 return DID_NOT_HANDLE; | 224 return DID_NOT_HANDLE; |
| 235 } | 225 } |
| 236 | 226 |
| 237 InputHandlerProxy::EventDisposition | |
| 238 InputHandlerProxy::HandleGestureFling( | |
| 239 const WebGestureEvent& gesture_event) { | |
| 240 cc::InputHandler::ScrollStatus scroll_status; | |
| 241 | |
| 242 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) { | |
| 243 scroll_status = input_handler_->ScrollBegin( | |
| 244 gfx::Point(gesture_event.x, gesture_event.y), | |
| 245 cc::InputHandler::NonBubblingGesture); | |
| 246 } else { | |
| 247 if (!gesture_scroll_on_impl_thread_) | |
| 248 scroll_status = cc::InputHandler::ScrollOnMainThread; | |
| 249 else | |
| 250 scroll_status = input_handler_->FlingScrollBegin(); | |
| 251 } | |
| 252 | |
| 253 #ifndef NDEBUG | |
| 254 expect_scroll_update_end_ = false; | |
| 255 #endif | |
| 256 | |
| 257 switch (scroll_status) { | |
| 258 case cc::InputHandler::ScrollStarted: { | |
| 259 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) | |
| 260 input_handler_->ScrollEnd(); | |
| 261 | |
| 262 fling_curve_.reset(client_->CreateFlingAnimationCurve( | |
| 263 gesture_event.sourceDevice, | |
| 264 WebFloatPoint(gesture_event.data.flingStart.velocityX, | |
| 265 gesture_event.data.flingStart.velocityY), | |
| 266 WebKit::WebSize())); | |
| 267 fling_overscrolled_horizontally_ = false; | |
| 268 fling_overscrolled_vertically_ = false; | |
| 269 TRACE_EVENT_ASYNC_BEGIN0( | |
| 270 "renderer", | |
| 271 "InputHandlerProxy::HandleGestureFling::started", | |
| 272 this); | |
| 273 fling_parameters_.delta = | |
| 274 WebFloatPoint(gesture_event.data.flingStart.velocityX, | |
| 275 gesture_event.data.flingStart.velocityY); | |
| 276 fling_parameters_.point = WebPoint(gesture_event.x, gesture_event.y); | |
| 277 fling_parameters_.globalPoint = | |
| 278 WebPoint(gesture_event.globalX, gesture_event.globalY); | |
| 279 fling_parameters_.modifiers = gesture_event.modifiers; | |
| 280 fling_parameters_.sourceDevice = gesture_event.sourceDevice; | |
| 281 input_handler_->ScheduleAnimation(); | |
| 282 return DID_HANDLE; | |
| 283 } | |
| 284 case cc::InputHandler::ScrollOnMainThread: { | |
| 285 TRACE_EVENT_INSTANT0("renderer", | |
| 286 "InputHandlerProxy::HandleGestureFling::" | |
| 287 "scroll_on_main_thread", | |
| 288 TRACE_EVENT_SCOPE_THREAD); | |
| 289 fling_may_be_active_on_main_thread_ = true; | |
| 290 return DID_NOT_HANDLE; | |
| 291 } | |
| 292 case cc::InputHandler::ScrollIgnored: { | |
| 293 TRACE_EVENT_INSTANT0( | |
| 294 "renderer", | |
| 295 "InputHandlerProxy::HandleGestureFling::ignored", | |
| 296 TRACE_EVENT_SCOPE_THREAD); | |
| 297 if (gesture_event.sourceDevice == WebGestureEvent::Touchpad) { | |
| 298 // We still pass the curve to the main thread if there's nothing | |
| 299 // scrollable, in case something | |
| 300 // registers a handler before the curve is over. | |
| 301 return DID_NOT_HANDLE; | |
| 302 } | |
| 303 return DROP_EVENT; | |
| 304 } | |
| 305 } | |
| 306 return DID_NOT_HANDLE; | |
| 307 } | |
| 308 | |
| 309 void InputHandlerProxy::Animate(base::TimeTicks time) { | 227 void InputHandlerProxy::Animate(base::TimeTicks time) { |
| 310 if (!fling_curve_) | |
| 311 return; | |
| 312 | |
| 313 double monotonic_time_sec = (time - base::TimeTicks()).InSecondsF(); | |
| 314 if (!fling_parameters_.startTime) { | |
| 315 fling_parameters_.startTime = monotonic_time_sec; | |
| 316 input_handler_->ScheduleAnimation(); | |
| 317 return; | |
| 318 } | |
| 319 | |
| 320 if (fling_curve_->apply(monotonic_time_sec - fling_parameters_.startTime, | |
| 321 this)) { | |
| 322 input_handler_->ScheduleAnimation(); | |
| 323 } else { | |
| 324 TRACE_EVENT_INSTANT0("renderer", | |
| 325 "InputHandlerProxy::animate::flingOver", | |
| 326 TRACE_EVENT_SCOPE_THREAD); | |
| 327 CancelCurrentFling(); | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 void InputHandlerProxy::MainThreadHasStoppedFlinging() { | |
| 332 fling_may_be_active_on_main_thread_ = false; | |
| 333 } | 228 } |
| 334 | 229 |
| 335 void InputHandlerProxy::DidOverscroll(const cc::DidOverscrollParams& params) { | 230 void InputHandlerProxy::DidOverscroll(const cc::DidOverscrollParams& params) { |
| 336 DCHECK(client_); | 231 DCHECK(client_); |
| 337 if (fling_curve_) { | |
| 338 static const int kFlingOverscrollThreshold = 1; | |
| 339 fling_overscrolled_horizontally_ |= | |
| 340 std::abs(params.accumulated_overscroll.x()) >= | |
| 341 kFlingOverscrollThreshold; | |
| 342 fling_overscrolled_vertically_ |= | |
| 343 std::abs(params.accumulated_overscroll.y()) >= | |
| 344 kFlingOverscrollThreshold; | |
| 345 } | |
| 346 | |
| 347 client_->DidOverscroll(params); | 232 client_->DidOverscroll(params); |
| 348 } | 233 } |
| 349 | 234 |
| 350 bool InputHandlerProxy::CancelCurrentFling() { | |
| 351 bool had_fling_animation = fling_curve_; | |
| 352 if (had_fling_animation && | |
| 353 fling_parameters_.sourceDevice == WebGestureEvent::Touchscreen) { | |
| 354 input_handler_->ScrollEnd(); | |
| 355 TRACE_EVENT_ASYNC_END0( | |
| 356 "renderer", | |
| 357 "InputHandlerProxy::HandleGestureFling::started", | |
| 358 this); | |
| 359 } | |
| 360 | |
| 361 TRACE_EVENT_INSTANT1("renderer", | |
| 362 "InputHandlerProxy::CancelCurrentFling", | |
| 363 TRACE_EVENT_SCOPE_THREAD, | |
| 364 "had_fling_animation", | |
| 365 had_fling_animation); | |
| 366 fling_curve_.reset(); | |
| 367 gesture_scroll_on_impl_thread_ = false; | |
| 368 fling_parameters_ = WebKit::WebActiveWheelFlingParameters(); | |
| 369 return had_fling_animation; | |
| 370 } | |
| 371 | |
| 372 bool InputHandlerProxy::TouchpadFlingScroll( | |
| 373 const WebFloatSize& increment) { | |
| 374 WebMouseWheelEvent synthetic_wheel; | |
| 375 synthetic_wheel.type = WebInputEvent::MouseWheel; | |
| 376 synthetic_wheel.deltaX = increment.width; | |
| 377 synthetic_wheel.deltaY = increment.height; | |
| 378 synthetic_wheel.hasPreciseScrollingDeltas = true; | |
| 379 synthetic_wheel.x = fling_parameters_.point.x; | |
| 380 synthetic_wheel.y = fling_parameters_.point.y; | |
| 381 synthetic_wheel.globalX = fling_parameters_.globalPoint.x; | |
| 382 synthetic_wheel.globalY = fling_parameters_.globalPoint.y; | |
| 383 synthetic_wheel.modifiers = fling_parameters_.modifiers; | |
| 384 | |
| 385 InputHandlerProxy::EventDisposition disposition = | |
| 386 HandleInputEvent(synthetic_wheel); | |
| 387 switch (disposition) { | |
| 388 case DID_HANDLE: | |
| 389 return true; | |
| 390 case DROP_EVENT: | |
| 391 break; | |
| 392 case DID_NOT_HANDLE: | |
| 393 TRACE_EVENT_INSTANT0("renderer", | |
| 394 "InputHandlerProxy::scrollBy::AbortFling", | |
| 395 TRACE_EVENT_SCOPE_THREAD); | |
| 396 // If we got a DID_NOT_HANDLE, that means we need to deliver wheels on the | |
| 397 // main thread. In this case we need to schedule a commit and transfer the | |
| 398 // fling curve over to the main thread and run the rest of the wheels from | |
| 399 // there. This can happen when flinging a page that contains a scrollable | |
| 400 // subarea that we can't scroll on the thread if the fling starts outside | |
| 401 // the subarea but then is flung "under" the pointer. | |
| 402 client_->TransferActiveWheelFlingAnimation(fling_parameters_); | |
| 403 fling_may_be_active_on_main_thread_ = true; | |
| 404 CancelCurrentFling(); | |
| 405 break; | |
| 406 } | |
| 407 | |
| 408 return false; | |
| 409 } | |
| 410 | |
| 411 static gfx::Vector2dF ToClientScrollIncrement(const WebFloatSize& increment) { | |
| 412 return gfx::Vector2dF(-increment.width, -increment.height); | |
| 413 } | |
| 414 | |
| 415 void InputHandlerProxy::scrollBy(const WebFloatSize& increment) { | |
| 416 WebFloatSize clipped_increment; | |
| 417 if (!fling_overscrolled_horizontally_) | |
| 418 clipped_increment.width = increment.width; | |
| 419 if (!fling_overscrolled_vertically_) | |
| 420 clipped_increment.height = increment.height; | |
| 421 | |
| 422 if (clipped_increment == WebFloatSize()) | |
| 423 return; | |
| 424 | |
| 425 TRACE_EVENT2("renderer", | |
| 426 "InputHandlerProxy::scrollBy", | |
| 427 "x", | |
| 428 clipped_increment.width, | |
| 429 "y", | |
| 430 clipped_increment.height); | |
| 431 | |
| 432 bool did_scroll = false; | |
| 433 | |
| 434 switch (fling_parameters_.sourceDevice) { | |
| 435 case WebGestureEvent::Touchpad: | |
| 436 did_scroll = TouchpadFlingScroll(clipped_increment); | |
| 437 break; | |
| 438 case WebGestureEvent::Touchscreen: | |
| 439 clipped_increment = ToClientScrollIncrement(clipped_increment); | |
| 440 did_scroll = input_handler_->ScrollBy(fling_parameters_.point, | |
| 441 clipped_increment); | |
| 442 break; | |
| 443 } | |
| 444 | |
| 445 if (did_scroll) { | |
| 446 fling_parameters_.cumulativeScroll.width += clipped_increment.width; | |
| 447 fling_parameters_.cumulativeScroll.height += clipped_increment.height; | |
| 448 } | |
| 449 } | |
| 450 | |
| 451 void InputHandlerProxy::notifyCurrentFlingVelocity( | |
| 452 const WebFloatSize& velocity) { | |
| 453 TRACE_EVENT2("renderer", | |
| 454 "InputHandlerProxy::notifyCurrentFlingVelocity", | |
| 455 "vx", | |
| 456 velocity.width, | |
| 457 "vy", | |
| 458 velocity.height); | |
| 459 input_handler_->NotifyCurrentFlingVelocity(ToClientScrollIncrement(velocity)); | |
| 460 } | |
| 461 | |
| 462 } // namespace content | 235 } // namespace content |
| OLD | NEW |