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