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 |