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 |