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