Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: content/renderer/gpu/input_handler_proxy.cc

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

Powered by Google App Engine
This is Rietveld 408576698