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

Side by Side Diff: content/browser/renderer_host/input/input_router_impl.cc

Issue 250923004: Synthesize ctrl-wheel events on touchpad pinch (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update conversion function Created 6 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
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 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/browser/renderer_host/input/input_router_impl.h" 5 #include "content/browser/renderer_host/input/input_router_impl.h"
6 6
7 #include <math.h>
8
7 #include "base/auto_reset.h" 9 #include "base/auto_reset.h"
8 #include "base/command_line.h" 10 #include "base/command_line.h"
9 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
11 #include "content/browser/renderer_host/input/gesture_event_queue.h" 13 #include "content/browser/renderer_host/input/gesture_event_queue.h"
12 #include "content/browser/renderer_host/input/input_ack_handler.h" 14 #include "content/browser/renderer_host/input/input_ack_handler.h"
13 #include "content/browser/renderer_host/input/input_router_client.h" 15 #include "content/browser/renderer_host/input/input_router_client.h"
14 #include "content/browser/renderer_host/input/touch_event_queue.h" 16 #include "content/browser/renderer_host/input/touch_event_queue.h"
15 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle r.h" 17 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controlle r.h"
16 #include "content/browser/renderer_host/overscroll_controller.h" 18 #include "content/browser/renderer_host/overscroll_controller.h"
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (mouse_event.event.type == WebInputEvent::MouseUp && 175 if (mouse_event.event.type == WebInputEvent::MouseUp &&
174 gesture_event_queue_.GetTouchpadTapSuppressionController()-> 176 gesture_event_queue_.GetTouchpadTapSuppressionController()->
175 ShouldSuppressMouseUp()) 177 ShouldSuppressMouseUp())
176 return; 178 return;
177 179
178 SendMouseEventImmediately(mouse_event); 180 SendMouseEventImmediately(mouse_event);
179 } 181 }
180 182
181 void InputRouterImpl::SendWheelEvent( 183 void InputRouterImpl::SendWheelEvent(
182 const MouseWheelEventWithLatencyInfo& wheel_event) { 184 const MouseWheelEventWithLatencyInfo& wheel_event) {
183 // If there's already a mouse wheel event waiting to be sent to the renderer, 185 SendWheelEvent(QueuedWheelEvent(wheel_event, false));
184 // add the new deltas to that event. Not doing so (e.g., by dropping the old 186 }
185 // event, as for mouse moves) results in very slow scrolling on the Mac (on 187
186 // which many, very small wheel events are sent). 188 void InputRouterImpl::SendWheelEvent(const QueuedWheelEvent& wheel_event) {
187 if (mouse_wheel_pending_) { 189 if (mouse_wheel_pending_) {
190 // If there's already a mouse wheel event waiting to be sent to the
191 // renderer, add the new deltas to that event. Not doing so (e.g., by
192 // dropping the old event, as for mouse moves) results in very slow
193 // scrolling on the Mac (on which many, very small wheel events are sent).
194 // Note that we can't coalesce wheel events for pinches because the GEQ
195 // expects one ACK for each (but it's fine to coalesce non-pinch wheels
196 // into a pinch one). Note that the GestureEventQueue ensures we only
197 // ever have a single pinch event queued here.
188 if (coalesced_mouse_wheel_events_.empty() || 198 if (coalesced_mouse_wheel_events_.empty() ||
189 !coalesced_mouse_wheel_events_.back().CanCoalesceWith(wheel_event)) { 199 wheel_event.synthesized_from_pinch ||
200 !coalesced_mouse_wheel_events_.back().event.CanCoalesceWith(
201 wheel_event.event)) {
190 coalesced_mouse_wheel_events_.push_back(wheel_event); 202 coalesced_mouse_wheel_events_.push_back(wheel_event);
191 } else { 203 } else {
192 coalesced_mouse_wheel_events_.back().CoalesceWith(wheel_event); 204 coalesced_mouse_wheel_events_.back().event.CoalesceWith(
205 wheel_event.event);
193 } 206 }
194 return; 207 return;
195 } 208 }
209
196 mouse_wheel_pending_ = true; 210 mouse_wheel_pending_ = true;
197 current_wheel_event_ = wheel_event; 211 current_wheel_event_ = wheel_event;
198 212
199 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize", 213 HISTOGRAM_COUNTS_100("Renderer.WheelQueueSize",
200 coalesced_mouse_wheel_events_.size()); 214 coalesced_mouse_wheel_events_.size());
201 215
202 FilterAndSendWebInputEvent(wheel_event.event, wheel_event.latency, false); 216 FilterAndSendWebInputEvent(
217 wheel_event.event.event, wheel_event.event.latency, false);
203 } 218 }
204 219
205 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event, 220 void InputRouterImpl::SendKeyboardEvent(const NativeWebKeyboardEvent& key_event,
206 const ui::LatencyInfo& latency_info, 221 const ui::LatencyInfo& latency_info,
207 bool is_keyboard_shortcut) { 222 bool is_keyboard_shortcut) {
208 // Put all WebKeyboardEvent objects in a queue since we can't trust the 223 // Put all WebKeyboardEvent objects in a queue since we can't trust the
209 // renderer and we need to give something to the HandleKeyboardEvent 224 // renderer and we need to give something to the HandleKeyboardEvent
210 // handler. 225 // handler.
211 key_queue_.push_back(key_event); 226 key_queue_.push_back(key_event);
212 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size()); 227 HISTOGRAM_COUNTS_100("Renderer.KeyboardQueueSize", key_queue_.size());
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 386
372 void InputRouterImpl::FilterAndSendWebInputEvent( 387 void InputRouterImpl::FilterAndSendWebInputEvent(
373 const WebInputEvent& input_event, 388 const WebInputEvent& input_event,
374 const ui::LatencyInfo& latency_info, 389 const ui::LatencyInfo& latency_info,
375 bool is_keyboard_shortcut) { 390 bool is_keyboard_shortcut) {
376 TRACE_EVENT1("input", 391 TRACE_EVENT1("input",
377 "InputRouterImpl::FilterAndSendWebInputEvent", 392 "InputRouterImpl::FilterAndSendWebInputEvent",
378 "type", 393 "type",
379 WebInputEventTraits::GetName(input_event.type)); 394 WebInputEventTraits::GetName(input_event.type));
380 395
381 // Transmit any pending wheel events on a non-wheel event. This ensures that
382 // final PhaseEnded wheel event is received, which is necessary to terminate
383 // rubber-banding, for example.
384 if (input_event.type != WebInputEvent::MouseWheel) {
385 WheelEventQueue mouse_wheel_events;
386 mouse_wheel_events.swap(coalesced_mouse_wheel_events_);
387 for (size_t i = 0; i < mouse_wheel_events.size(); ++i) {
388 OfferToHandlers(mouse_wheel_events[i].event,
389 mouse_wheel_events[i].latency,
390 false);
391 }
392 }
393
394 // Any input event cancels a pending mouse move event. 396 // Any input event cancels a pending mouse move event.
395 next_mouse_move_.reset(); 397 next_mouse_move_.reset();
396 398
397 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut); 399 OfferToHandlers(input_event, latency_info, is_keyboard_shortcut);
398 } 400 }
399 401
400 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event, 402 void InputRouterImpl::OfferToHandlers(const WebInputEvent& input_event,
401 const ui::LatencyInfo& latency_info, 403 const ui::LatencyInfo& latency_info,
402 bool is_keyboard_shortcut) { 404 bool is_keyboard_shortcut) {
403 // Trackpad pinch gestures are not yet handled by the renderer. 405 if (input_event.type == WebInputEvent::GesturePinchUpdate) {
404 // TODO(rbyers): Send mousewheel for trackpad pinch - crbug.com/289887. 406 const WebGestureEvent& pinch_event =
405 if (input_event.type == WebInputEvent::GesturePinchUpdate && 407 static_cast<const WebGestureEvent&>(input_event);
406 static_cast<const WebGestureEvent&>(input_event).sourceDevice == 408 if (pinch_event.sourceDevice == WebGestureEvent::Touchpad) {
407 WebGestureEvent::Touchpad) { 409 SendSyntheticWheelEventForPinch(pinch_event, latency_info);
408 ProcessInputEventAck(input_event.type, 410 return;
409 INPUT_EVENT_ACK_STATE_NOT_CONSUMED, 411 }
410 latency_info,
411 ACK_SOURCE_NONE);
412 return;
413 } 412 }
414 413
415 if (OfferToOverscrollController(input_event, latency_info)) 414 if (OfferToOverscrollController(input_event, latency_info))
416 return; 415 return;
417 416
418 if (OfferToClient(input_event, latency_info)) 417 if (OfferToClient(input_event, latency_info))
419 return; 418 return;
420 419
421 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut); 420 OfferToRenderer(input_event, latency_info, is_keyboard_shortcut);
422 421
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 // or in-flight event count metrics. 507 // or in-flight event count metrics.
509 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) { 508 if (!WebInputEventTraits::IgnoresAckDisposition(input_event)) {
510 input_event_start_time_ = TimeTicks::Now(); 509 input_event_start_time_ = TimeTicks::Now();
511 client_->IncrementInFlightEventCount(); 510 client_->IncrementInFlightEventCount();
512 } 511 }
513 return true; 512 return true;
514 } 513 }
515 return false; 514 return false;
516 } 515 }
517 516
517 void InputRouterImpl::SendSyntheticWheelEventForPinch(
518 const blink::WebGestureEvent& pinch_event,
519 const ui::LatencyInfo& latency_info) {
520 // We match typical trackpad behavior on Windows by sending fake wheel events
521 // with the ctrl modifier set when we see trackpad pinch gestures. Ideally
522 // we'd someday get a standard 'pinch' event and send that instead.
523
524 WebMouseWheelEvent wheelEvent;
525 wheelEvent.type = WebInputEvent::MouseWheel;
526 wheelEvent.timeStampSeconds = pinch_event.timeStampSeconds;
527 wheelEvent.windowX = wheelEvent.x = pinch_event.x;
528 wheelEvent.windowY = wheelEvent.y = pinch_event.y;
529 wheelEvent.globalX = pinch_event.globalX;
530 wheelEvent.globalY = pinch_event.globalY;
531 wheelEvent.modifiers = pinch_event.modifiers | WebInputEvent::ControlKey;
532 wheelEvent.deltaX = 0;
533 // The function to convert scales to deltaY values is designed to be
534 // compatible with websites existing use of wheel events, and with existing
535 // Windows trackpad behavior. In particular, we want:
536 // - deltas should accumulate via addition: f(s1*s2)==f(s1)+f(s2)
537 // - deltas should invert via negation: f(1/s) == -f(s)
538 // - zoom in should be positive: f(s) > 0 iff s > 1
539 // - magnitude roughly matches wheels: f(2) > 25 && f(2) < 100
540 // - a formula that's relatively easy to use from JavaScript
541 // Note that 'wheel' event deltaY values have their sign inverted. So to
542 // convert a wheel deltaY back to a scale use Math.exp(-deltaY/100).
543 wheelEvent.deltaY = 100.0f * log(pinch_event.data.pinchUpdate.scale);
544 wheelEvent.hasPreciseScrollingDeltas = true;
545 wheelEvent.wheelTicksX = 0;
546 wheelEvent.wheelTicksY = pinch_event.data.pinchUpdate.scale > 1 ? 1 : -1;
547
548 SendWheelEvent(QueuedWheelEvent(
549 MouseWheelEventWithLatencyInfo(wheelEvent, latency_info), true));
550 }
551
518 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type, 552 void InputRouterImpl::OnInputEventAck(WebInputEvent::Type event_type,
519 InputEventAckState ack_result, 553 InputEventAckState ack_result,
520 const ui::LatencyInfo& latency_info) { 554 const ui::LatencyInfo& latency_info) {
521 client_->DecrementInFlightEventCount(); 555 client_->DecrementInFlightEventCount();
522 556
523 // Log the time delta for processing an input event. 557 // Log the time delta for processing an input event.
524 TimeDelta delta = TimeTicks::Now() - input_event_start_time_; 558 TimeDelta delta = TimeTicks::Now() - input_event_start_time_;
525 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta); 559 UMA_HISTOGRAM_TIMES("MPArch.IIR_InputEventDelta", delta);
526 560
527 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER); 561 ProcessInputEventAck(event_type, ack_result, latency_info, RENDERER);
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 if (next_mouse_move_) { 674 if (next_mouse_move_) {
641 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove); 675 DCHECK(next_mouse_move_->event.type == WebInputEvent::MouseMove);
642 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move 676 scoped_ptr<MouseEventWithLatencyInfo> next_mouse_move
643 = next_mouse_move_.Pass(); 677 = next_mouse_move_.Pass();
644 SendMouseEvent(*next_mouse_move); 678 SendMouseEvent(*next_mouse_move);
645 } 679 }
646 } 680 }
647 681
648 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result, 682 void InputRouterImpl::ProcessWheelAck(InputEventAckState ack_result,
649 const ui::LatencyInfo& latency) { 683 const ui::LatencyInfo& latency) {
650 ProcessAckForOverscroll(current_wheel_event_.event, ack_result);
651
652 // TODO(miletus): Add renderer side latency to each uncoalesced mouse 684 // TODO(miletus): Add renderer side latency to each uncoalesced mouse
653 // wheel event and add terminal component to each of them. 685 // wheel event and add terminal component to each of them.
654 current_wheel_event_.latency.AddNewLatencyFrom(latency); 686 current_wheel_event_.event.latency.AddNewLatencyFrom(latency);
655 // Process the unhandled wheel event here before calling SendWheelEvent() 687
656 // since it will mutate current_wheel_event_. 688 if (current_wheel_event_.synthesized_from_pinch) {
657 ack_handler_->OnWheelEventAck(current_wheel_event_, ack_result); 689 // Ack the GesturePinchUpdate event that generated this wheel event.
690 ProcessInputEventAck(WebInputEvent::GesturePinchUpdate,
691 ack_result,
692 current_wheel_event_.event.latency,
693 ACK_SOURCE_NONE);
694 } else {
695 // Process the unhandled wheel event here before calling SendWheelEvent()
696 // since it will mutate current_wheel_event_.
697 ProcessAckForOverscroll(current_wheel_event_.event.event, ack_result);
698 ack_handler_->OnWheelEventAck(current_wheel_event_.event, ack_result);
699 }
658 mouse_wheel_pending_ = false; 700 mouse_wheel_pending_ = false;
659 701
660 // Now send the next (coalesced) mouse wheel event. 702 // Send the next (coalesced or synthetic) mouse wheel event.
661 if (!coalesced_mouse_wheel_events_.empty()) { 703 if (!coalesced_mouse_wheel_events_.empty()) {
662 MouseWheelEventWithLatencyInfo next_wheel_event = 704 QueuedWheelEvent next_wheel_event = coalesced_mouse_wheel_events_.front();
663 coalesced_mouse_wheel_events_.front();
664 coalesced_mouse_wheel_events_.pop_front(); 705 coalesced_mouse_wheel_events_.pop_front();
665 SendWheelEvent(next_wheel_event); 706 SendWheelEvent(next_wheel_event);
666 } 707 }
667 } 708 }
668 709
669 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type, 710 void InputRouterImpl::ProcessGestureAck(WebInputEvent::Type type,
670 InputEventAckState ack_result, 711 InputEventAckState ack_result,
671 const ui::LatencyInfo& latency) { 712 const ui::LatencyInfo& latency) {
672 // If |ack_result| originated from the overscroll controller, only 713 // If |ack_result| originated from the overscroll controller, only
673 // feed |gesture_event_queue_| the ack if it was expecting one. 714 // feed |gesture_event_queue_| the ack if it was expecting one.
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
745 mouse_wheel_pending_ || 786 mouse_wheel_pending_ ||
746 select_range_pending_ || 787 select_range_pending_ ||
747 move_caret_pending_; 788 move_caret_pending_;
748 } 789 }
749 790
750 bool InputRouterImpl::IsInOverscrollGesture() const { 791 bool InputRouterImpl::IsInOverscrollGesture() const {
751 OverscrollController* controller = client_->GetOverscrollController(); 792 OverscrollController* controller = client_->GetOverscrollController();
752 return controller && controller->overscroll_mode() != OVERSCROLL_NONE; 793 return controller && controller->overscroll_mode() != OVERSCROLL_NONE;
753 } 794 }
754 795
796 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent() {
797 }
798
799 InputRouterImpl::QueuedWheelEvent::QueuedWheelEvent(
800 const MouseWheelEventWithLatencyInfo& event,
801 bool synthesized_from_pinch)
802 : event(event), synthesized_from_pinch(synthesized_from_pinch) {
803 }
804
805 InputRouterImpl::QueuedWheelEvent::~QueuedWheelEvent() {
806 }
807
755 } // namespace content 808 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698