| OLD | NEW |
| 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/synthetic_pinch_gesture.h" | 5 #include "content/browser/renderer_host/input/synthetic_pinch_gesture.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "content/common/input/input_event.h" | 10 #include "content/common/input/input_event.h" |
| 11 #include "ui/events/latency_info.h" | 11 #include "ui/events/latency_info.h" |
| 12 | 12 |
| 13 namespace content { | 13 namespace content { |
| 14 | 14 |
| 15 SyntheticPinchGesture::SyntheticPinchGesture( | 15 SyntheticPinchGesture::SyntheticPinchGesture( |
| 16 const SyntheticPinchGestureParams& params) | 16 const SyntheticPinchGestureParams& params) |
| 17 : params_(params), | 17 : params_(params), |
| 18 current_y_0_(0.0f), | 18 start_y_0_(0.0f), |
| 19 current_y_1_(0.0f), | 19 start_y_1_(0.0f), |
| 20 target_y_0_(0.0f), | 20 target_y_0_(0.0f), |
| 21 target_y_1_(0.0f), | 21 target_y_1_(0.0f), |
| 22 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT), | 22 gesture_source_type_(SyntheticGestureParams::DEFAULT_INPUT), |
| 23 state_(SETUP) { | 23 state_(SETUP) { |
| 24 DCHECK_GE(params_.total_num_pixels_covered, 0); | 24 DCHECK_GE(params_.total_num_pixels_covered, 0); |
| 25 } | 25 } |
| 26 | 26 |
| 27 SyntheticPinchGesture::~SyntheticPinchGesture() {} | 27 SyntheticPinchGesture::~SyntheticPinchGesture() {} |
| 28 | 28 |
| 29 SyntheticGesture::Result SyntheticPinchGesture::ForwardInputEvents( | 29 SyntheticGesture::Result SyntheticPinchGesture::ForwardInputEvents( |
| 30 const base::TimeDelta& interval, SyntheticGestureTarget* target) { | 30 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { |
| 31 if (state_ == SETUP) { | 31 if (state_ == SETUP) { |
| 32 gesture_source_type_ = params_.gesture_source_type; | 32 gesture_source_type_ = params_.gesture_source_type; |
| 33 if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT) | 33 if (gesture_source_type_ == SyntheticGestureParams::DEFAULT_INPUT) |
| 34 gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType(); | 34 gesture_source_type_ = target->GetDefaultSyntheticGestureSourceType(); |
| 35 | 35 |
| 36 if (!target->SupportsSyntheticGestureSourceType(gesture_source_type_)) | 36 if (!target->SupportsSyntheticGestureSourceType(gesture_source_type_)) |
| 37 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM; | 37 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_SUPPORTED_BY_PLATFORM; |
| 38 | 38 |
| 39 state_ = STARTED; | 39 state_ = STARTED; |
| 40 start_time_ = timestamp; |
| 40 } | 41 } |
| 41 | 42 |
| 42 DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT); | 43 DCHECK_NE(gesture_source_type_, SyntheticGestureParams::DEFAULT_INPUT); |
| 43 if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT) | 44 if (gesture_source_type_ == SyntheticGestureParams::TOUCH_INPUT) |
| 44 ForwardTouchInputEvents(interval, target); | 45 ForwardTouchInputEvents(timestamp, target); |
| 45 else | 46 else |
| 46 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; | 47 return SyntheticGesture::GESTURE_SOURCE_TYPE_NOT_IMPLEMENTED; |
| 47 | 48 |
| 48 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED | 49 return (state_ == DONE) ? SyntheticGesture::GESTURE_FINISHED |
| 49 : SyntheticGesture::GESTURE_RUNNING; | 50 : SyntheticGesture::GESTURE_RUNNING; |
| 50 } | 51 } |
| 51 | 52 |
| 52 void SyntheticPinchGesture::ForwardTouchInputEvents( | 53 void SyntheticPinchGesture::ForwardTouchInputEvents( |
| 53 const base::TimeDelta& interval, SyntheticGestureTarget* target) { | 54 const base::TimeTicks& timestamp, SyntheticGestureTarget* target) { |
| 54 switch (state_) { | 55 switch (state_) { |
| 55 case STARTED: | 56 case STARTED: |
| 56 // Check for an early finish. | 57 // Check for an early finish. |
| 57 if (params_.total_num_pixels_covered == 0) { | 58 if (params_.total_num_pixels_covered == 0) { |
| 58 state_ = DONE; | 59 state_ = DONE; |
| 59 break; | 60 break; |
| 60 } | 61 } |
| 61 SetupCoordinates(target); | 62 SetupCoordinates(target); |
| 62 PressTouchPoints(target); | 63 PressTouchPoints(target, timestamp); |
| 63 state_ = MOVING; | 64 state_ = MOVING; |
| 64 break; | 65 break; |
| 65 case MOVING: | 66 case MOVING: { |
| 66 UpdateTouchPoints(interval); | 67 base::TimeTicks event_timestamp = timestamp; |
| 67 MoveTouchPoints(target); | 68 float delta = GetDeltaForPointer0AndUpdateTimestamp(&event_timestamp); |
| 68 if (HasReachedTarget()) { | 69 MoveTouchPoints(target, delta, event_timestamp); |
| 69 ReleaseTouchPoints(target); | 70 if (HasReachedTarget(delta)) { |
| 71 ReleaseTouchPoints(target, event_timestamp); |
| 70 state_ = DONE; | 72 state_ = DONE; |
| 71 } | 73 } |
| 72 break; | 74 } break; |
| 73 case SETUP: | 75 case SETUP: |
| 74 NOTREACHED() << "State SETUP invalid for synthetic pinch."; | 76 NOTREACHED() << "State SETUP invalid for synthetic pinch."; |
| 75 case DONE: | 77 case DONE: |
| 76 NOTREACHED() << "State DONE invalid for synthetic pinch."; | 78 NOTREACHED() << "State DONE invalid for synthetic pinch."; |
| 77 } | 79 } |
| 78 } | 80 } |
| 79 | 81 |
| 80 void SyntheticPinchGesture::UpdateTouchPoints(base::TimeDelta interval) { | 82 void SyntheticPinchGesture::PressTouchPoints(SyntheticGestureTarget* target, |
| 81 // Compute the delta for the first pointer. The other one moves exactly | 83 const base::TimeTicks& timestamp) { |
| 82 // the same but in the opposite direction. | 84 touch_event_.PressPoint(params_.anchor.x(), start_y_0_); |
| 83 float delta = GetDeltaForPointer0(interval); | 85 touch_event_.PressPoint(params_.anchor.x(), start_y_1_); |
| 84 current_y_0_ += delta; | 86 ForwardTouchEvent(target, timestamp); |
| 85 current_y_1_ -= delta; | |
| 86 } | 87 } |
| 87 | 88 |
| 88 void SyntheticPinchGesture::PressTouchPoints(SyntheticGestureTarget* target) { | 89 void SyntheticPinchGesture::MoveTouchPoints(SyntheticGestureTarget* target, |
| 89 touch_event_.PressPoint(params_.anchor.x(), current_y_0_); | 90 float delta, |
| 90 touch_event_.PressPoint(params_.anchor.x(), current_y_1_); | 91 const base::TimeTicks& timestamp) { |
| 91 ForwardTouchEvent(target); | 92 // The two pointers move in opposite directions. |
| 92 } | 93 float current_y_0 = start_y_0_ + delta; |
| 94 float current_y_1 = start_y_1_ - delta; |
| 93 | 95 |
| 94 void SyntheticPinchGesture::MoveTouchPoints(SyntheticGestureTarget* target) { | |
| 95 // The current pointer positions are stored as float but the pointer | 96 // The current pointer positions are stored as float but the pointer |
| 96 // coordinates of the input event are integers. Floor both positions so that | 97 // coordinates of the input event are integers. Floor both positions so that |
| 97 // in case of an odd distance one of the pointers (the one whose position goes | 98 // in case of an odd distance one of the pointers (the one whose position goes |
| 98 // down) moves one pixel further than the other. The explicit flooring is only | 99 // down) moves one pixel further than the other. The explicit flooring is only |
| 99 // needed for negative values. | 100 // needed for negative values. |
| 100 touch_event_.MovePoint(0, params_.anchor.x(), floor(current_y_0_)); | 101 touch_event_.MovePoint(0, params_.anchor.x(), floor(current_y_0)); |
| 101 touch_event_.MovePoint(1, params_.anchor.x(), floor(current_y_1_)); | 102 touch_event_.MovePoint(1, params_.anchor.x(), floor(current_y_1)); |
| 102 ForwardTouchEvent(target); | 103 ForwardTouchEvent(target, timestamp); |
| 103 } | 104 } |
| 104 | 105 |
| 105 void SyntheticPinchGesture::ReleaseTouchPoints(SyntheticGestureTarget* target) { | 106 void SyntheticPinchGesture::ReleaseTouchPoints( |
| 107 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) { |
| 106 touch_event_.ReleasePoint(0); | 108 touch_event_.ReleasePoint(0); |
| 107 touch_event_.ReleasePoint(1); | 109 touch_event_.ReleasePoint(1); |
| 108 ForwardTouchEvent(target); | 110 ForwardTouchEvent(target, timestamp); |
| 109 } | 111 } |
| 110 | 112 |
| 111 | 113 void SyntheticPinchGesture::ForwardTouchEvent( |
| 112 void SyntheticPinchGesture::ForwardTouchEvent(SyntheticGestureTarget* target) | 114 SyntheticGestureTarget* target, const base::TimeTicks& timestamp) { |
| 113 const { | 115 touch_event_.timeStampSeconds = ConvertTimestampToSeconds(timestamp); |
| 114 target->DispatchInputEventToPlatform( | 116 target->DispatchInputEventToPlatform( |
| 115 InputEvent(touch_event_, ui::LatencyInfo(), false)); | 117 InputEvent(touch_event_, ui::LatencyInfo(), false)); |
| 116 } | 118 } |
| 117 | 119 |
| 118 void SyntheticPinchGesture::SetupCoordinates(SyntheticGestureTarget* target) { | 120 void SyntheticPinchGesture::SetupCoordinates(SyntheticGestureTarget* target) { |
| 119 const float kTouchSlopInDips = target->GetTouchSlopInDips(); | 121 const int kTouchSlopInDips = target->GetTouchSlopInDips(); |
| 122 params_.total_num_pixels_covered += 2 * kTouchSlopInDips; |
| 120 float inner_distance_to_anchor = 2 * kTouchSlopInDips; | 123 float inner_distance_to_anchor = 2 * kTouchSlopInDips; |
| 121 float outer_distance_to_anchor = inner_distance_to_anchor + | 124 float outer_distance_to_anchor = inner_distance_to_anchor + |
| 122 params_.total_num_pixels_covered / 2.0f + | 125 params_.total_num_pixels_covered / 2.0f; |
| 123 kTouchSlopInDips; | |
| 124 | 126 |
| 125 // Move pointers away from each other to zoom in | 127 // Move pointers away from each other to zoom in |
| 126 // or towards each other to zoom out. | 128 // or towards each other to zoom out. |
| 127 if (params_.zoom_in) { | 129 if (params_.zoom_in) { |
| 128 current_y_0_ = params_.anchor.y() - inner_distance_to_anchor; | 130 start_y_0_ = params_.anchor.y() - inner_distance_to_anchor; |
| 129 current_y_1_ = params_.anchor.y() + inner_distance_to_anchor; | 131 start_y_1_ = params_.anchor.y() + inner_distance_to_anchor; |
| 130 target_y_0_ = params_.anchor.y() - outer_distance_to_anchor; | 132 target_y_0_ = params_.anchor.y() - outer_distance_to_anchor; |
| 131 target_y_1_ = params_.anchor.y() + outer_distance_to_anchor; | 133 target_y_1_ = params_.anchor.y() + outer_distance_to_anchor; |
| 132 } else { | 134 } else { |
| 133 current_y_0_ = params_.anchor.y() - outer_distance_to_anchor; | 135 start_y_0_ = params_.anchor.y() - outer_distance_to_anchor; |
| 134 current_y_1_ = params_.anchor.y() + outer_distance_to_anchor; | 136 start_y_1_ = params_.anchor.y() + outer_distance_to_anchor; |
| 135 target_y_0_ = params_.anchor.y() - inner_distance_to_anchor; | 137 target_y_0_ = params_.anchor.y() - inner_distance_to_anchor; |
| 136 target_y_1_ = params_.anchor.y() + inner_distance_to_anchor; | 138 target_y_1_ = params_.anchor.y() + inner_distance_to_anchor; |
| 137 } | 139 } |
| 138 } | 140 } |
| 139 | 141 |
| 140 float SyntheticPinchGesture::GetDeltaForPointer0( | 142 float SyntheticPinchGesture::GetDeltaForPointer0AndUpdateTimestamp( |
| 141 const base::TimeDelta& interval) const { | 143 base::TimeTicks* timestamp) const { |
| 142 float total_abs_delta = | 144 DCHECK(timestamp); |
| 143 params_.relative_pointer_speed_in_pixels_s * interval.InSecondsF(); | 145 float total_abs_delta = params_.relative_pointer_speed_in_pixels_s * |
| 146 (*timestamp - start_time_).InSecondsF(); |
| 144 | 147 |
| 145 // Make sure we're not moving too far in the final step. | 148 // Make sure we're not moving too far in the final step. |
| 146 total_abs_delta = | 149 if (total_abs_delta > params_.total_num_pixels_covered) { |
| 147 std::min(total_abs_delta, ComputeAbsoluteRemainingDistance()); | 150 total_abs_delta = params_.total_num_pixels_covered; |
| 148 | 151 |
| 149 float abs_delta_pointer_0 = total_abs_delta / 2; | 152 // Update timestamp to match the end of the gesture. |
| 153 int total_duration_in_ms = static_cast<int>( |
| 154 1000.0f * (params_.total_num_pixels_covered / |
| 155 params_.relative_pointer_speed_in_pixels_s)); |
| 156 *timestamp = |
| 157 start_time_ + base::TimeDelta::FromMilliseconds(total_duration_in_ms); |
| 158 } |
| 159 |
| 160 float abs_delta_pointer_0 = total_abs_delta / 2.0f; |
| 150 return params_.zoom_in ? -abs_delta_pointer_0 : abs_delta_pointer_0; | 161 return params_.zoom_in ? -abs_delta_pointer_0 : abs_delta_pointer_0; |
| 151 } | 162 } |
| 152 | 163 |
| 153 float SyntheticPinchGesture::ComputeAbsoluteRemainingDistance() const { | 164 bool SyntheticPinchGesture::HasReachedTarget(float delta) const { |
| 154 float distance_0 = params_.zoom_in ? (current_y_0_ - target_y_0_) | 165 return start_y_0_ + delta == target_y_0_; |
| 155 : (target_y_0_ - current_y_0_); | |
| 156 DCHECK_GE(distance_0, 0); | |
| 157 | |
| 158 // Both pointers move the same overall distance at the same speed. | |
| 159 return 2 * distance_0; | |
| 160 } | |
| 161 | |
| 162 bool SyntheticPinchGesture::HasReachedTarget() const { | |
| 163 return ComputeAbsoluteRemainingDistance() == 0; | |
| 164 } | 166 } |
| 165 | 167 |
| 166 } // namespace content | 168 } // namespace content |
| OLD | NEW |