Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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/browser/renderer_host/input/touch_selection_controller.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
| 9 | |
| 10 namespace content { | |
| 11 | |
| 12 TouchSelectionController::TouchSelectionController( | |
| 13 TouchSelectionControllerClient* client) | |
| 14 : client_(client), | |
| 15 start_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | |
| 16 start_visible_(false), | |
| 17 end_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | |
| 18 end_visible_(false), | |
| 19 is_insertion_active_(false), | |
| 20 allow_automatic_insertion_activation_(false), | |
| 21 is_selection_active_(false), | |
| 22 allow_automatic_selection_activation_(false), | |
| 23 selection_editable_(false), | |
| 24 selection_editable_for_last_update_(false) { | |
| 25 DCHECK(client_); | |
| 26 HideAndDisallowAutomaticShowing(); | |
| 27 } | |
| 28 | |
| 29 TouchSelectionController::~TouchSelectionController() { | |
| 30 } | |
| 31 | |
| 32 void TouchSelectionController::OnSelectionBoundsChanged( | |
| 33 const gfx::RectF& start_rect, | |
| 34 TouchHandleOrientation start_orientation, | |
| 35 bool start_visible, | |
| 36 const gfx::RectF& end_rect, | |
| 37 TouchHandleOrientation end_orientation, | |
| 38 bool end_visible) { | |
| 39 if (!allow_automatic_selection_activation_ && | |
| 40 !allow_automatic_insertion_activation_) | |
| 41 return; | |
| 42 | |
| 43 if (start_rect_ == start_rect && end_rect_ == end_rect && | |
| 44 start_orientation_ == start_orientation && | |
| 45 end_orientation_ == end_orientation && | |
| 46 start_visible_ == start_visible && end_visible_ == end_visible && | |
| 47 selection_editable_ == selection_editable_for_last_update_) | |
| 48 return; | |
| 49 | |
| 50 start_rect_ = start_rect; | |
| 51 start_orientation_ = start_orientation; | |
| 52 start_visible_ = start_visible; | |
| 53 end_rect_ = end_rect; | |
| 54 end_orientation_ = end_orientation; | |
| 55 end_visible_ = end_visible; | |
| 56 selection_editable_for_last_update_ = selection_editable_; | |
| 57 | |
| 58 const bool is_selection_dragging = | |
| 59 is_selection_active_ && (start_selection_handle_->is_dragging() || | |
| 60 end_selection_handle_->is_dragging()); | |
| 61 | |
| 62 // It's possible that the bounds temporarily overlap while a selection handle | |
| 63 // is being dragged, incorrectly reporting a CENTER orientation. | |
| 64 // TODO(jdduke): This safeguard is racy, as it's possible the delayed response | |
| 65 // from handle positioning occurs *after* the handle dragging has ceased. | |
| 66 // Instead, prevent selection -> insertion transitions without an intervening | |
| 67 // action or selection clearing of some sort, crbug.com/392696. | |
| 68 if (is_selection_dragging) { | |
| 69 if (start_orientation_ == TOUCH_HANDLE_CENTER) | |
| 70 start_orientation_ = start_selection_handle_->orientation(); | |
| 71 if (end_orientation_ == TOUCH_HANDLE_CENTER) | |
| 72 end_orientation_ = end_selection_handle_->orientation(); | |
| 73 } | |
| 74 | |
| 75 const gfx::PointF start = GetStartPosition(); | |
| 76 const gfx::PointF end = GetEndPosition(); | |
| 77 if (start != end || is_selection_dragging) { | |
| 78 OnSelectionChanged(); | |
| 79 return; | |
| 80 } | |
| 81 | |
| 82 if (start_orientation_ == TOUCH_HANDLE_CENTER) { | |
| 83 OnInsertionChanged(); | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 HideAndDisallowAutomaticShowing(); | |
| 88 } | |
| 89 | |
| 90 bool TouchSelectionController::WillHandleTouchEvent( | |
| 91 const ui::MotionEvent& event) { | |
| 92 if (is_insertion_active_) { | |
| 93 DCHECK(insertion_handle_); | |
| 94 return insertion_handle_->WillHandleTouchEvent(event); | |
| 95 } | |
| 96 | |
| 97 if (is_selection_active_) { | |
| 98 DCHECK(start_selection_handle_); | |
| 99 DCHECK(end_selection_handle_); | |
| 100 return start_selection_handle_->WillHandleTouchEvent(event) || | |
| 101 end_selection_handle_->WillHandleTouchEvent(event); | |
| 102 } | |
| 103 | |
| 104 return false; | |
| 105 } | |
| 106 | |
| 107 void TouchSelectionController::AllowAutomaticInsertionShowing() { | |
| 108 if (allow_automatic_insertion_activation_) | |
| 109 return; | |
| 110 allow_automatic_insertion_activation_ = true; | |
| 111 if (!is_insertion_active_ && !is_selection_active_) | |
| 112 ResetCachedValues(); | |
| 113 } | |
| 114 | |
| 115 void TouchSelectionController::AllowAutomaticSelectionShowing() { | |
| 116 if (allow_automatic_selection_activation_) | |
| 117 return; | |
| 118 allow_automatic_selection_activation_ = true; | |
| 119 if (!is_insertion_active_ && !is_selection_active_) | |
| 120 ResetCachedValues(); | |
| 121 } | |
| 122 | |
| 123 void TouchSelectionController::HideAndDisallowAutomaticShowing() { | |
| 124 DeactivateInsertion(); | |
| 125 DeactivateSelection(); | |
| 126 allow_automatic_insertion_activation_ = false; | |
| 127 allow_automatic_selection_activation_ = false; | |
| 128 } | |
| 129 | |
| 130 void TouchSelectionController::OnSelectionEditable(bool editable) { | |
| 131 if (selection_editable_ == editable) | |
| 132 return; | |
| 133 selection_editable_ = editable; | |
| 134 if (!selection_editable_) | |
| 135 DeactivateInsertion(); | |
| 136 } | |
| 137 | |
| 138 bool TouchSelectionController::Animate(base::TimeTicks frame_time) { | |
| 139 if (is_insertion_active_) | |
| 140 return insertion_handle_->Animate(frame_time); | |
| 141 | |
| 142 if (is_selection_active_) { | |
| 143 bool needs_animate = start_selection_handle_->Animate(frame_time); | |
| 144 needs_animate |= end_selection_handle_->Animate(frame_time); | |
| 145 return needs_animate; | |
| 146 } | |
| 147 | |
| 148 return false; | |
| 149 } | |
| 150 | |
| 151 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { | |
| 152 if (&handle == insertion_handle_.get()) | |
| 153 return; | |
| 154 | |
| 155 if (&handle == start_selection_handle_.get()) { | |
| 156 fixed_handle_position_ = end_selection_handle_->position() - | |
| 157 gfx::Vector2dF(0, GetEndLineHeight() / 2.f); | |
| 158 } else { | |
| 159 fixed_handle_position_ = start_selection_handle_->position() - | |
| 160 gfx::Vector2dF(0, GetStartLineHeight() / 2.f); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, | |
| 165 const gfx::PointF& position) { | |
| 166 // As the position corresponds to the bottom left point of the selection | |
| 167 // bound, offset it by half the corresponding line height. | |
| 168 float half_line_height = &handle == end_selection_handle_.get() | |
| 169 ? GetEndLineHeight() / 2.f | |
| 170 : GetStartLineHeight() / 2.f; | |
| 171 gfx::PointF line_position = position - gfx::Vector2dF(0, half_line_height); | |
| 172 if (&handle == insertion_handle_.get()) { | |
| 173 client_->MoveCaret(line_position); | |
| 174 } else { | |
| 175 client_->SelectBetweenCoordinates(fixed_handle_position_, line_position); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) { | |
| 180 } | |
| 181 | |
| 182 void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) { | |
| 183 if (insertion_handle_ && &handle == insertion_handle_.get()) | |
| 184 client_->OnSelectionEvent(INSERTION_TAPPED, GetStartPosition()); | |
| 185 } | |
| 186 | |
| 187 void TouchSelectionController::SetNeedsAnimate() { | |
| 188 client_->SetNeedsAnimate(); | |
| 189 } | |
| 190 | |
| 191 scoped_ptr<TouchHandleDrawable> TouchSelectionController::CreateDrawable() { | |
| 192 return client_->CreateDrawable(); | |
| 193 } | |
| 194 | |
| 195 void TouchSelectionController::OnInsertionChanged() { | |
| 196 DeactivateSelection(); | |
| 197 | |
| 198 if (!allow_automatic_insertion_activation_ || !selection_editable_) | |
| 199 return; | |
| 200 | |
| 201 gfx::PointF position = GetStartPosition(); | |
| 202 if (!is_insertion_active_) | |
| 203 ActivateInsertion(); | |
| 204 else | |
| 205 client_->OnSelectionEvent(INSERTION_MOVED, position); | |
| 206 | |
| 207 insertion_handle_->SetVisible(start_visible_, GetAnimationStyle()); | |
|
cjhopman
2014/07/14 18:23:52
This now fades in when first activated?
jdduke (slow)
2014/07/15 15:44:25
Bah, yeah, I played with this locally and thought
| |
| 208 insertion_handle_->SetPosition(position); | |
| 209 } | |
| 210 | |
| 211 void TouchSelectionController::OnSelectionChanged() { | |
| 212 DeactivateInsertion(); | |
| 213 | |
| 214 if (!allow_automatic_selection_activation_) | |
| 215 return; | |
| 216 | |
| 217 ActivateSelection(); | |
| 218 | |
| 219 const TouchHandle::AnimationStyle animation = GetAnimationStyle(); | |
|
cjhopman
2014/07/14 18:23:52
This also now fades in?
jdduke (slow)
2014/07/15 15:44:25
Yeah but I'll revert.
| |
| 220 start_selection_handle_->SetVisible(start_visible_, animation); | |
| 221 end_selection_handle_->SetVisible(end_visible_, animation); | |
| 222 | |
| 223 start_selection_handle_->SetPosition(GetStartPosition()); | |
| 224 end_selection_handle_->SetPosition(GetEndPosition()); | |
| 225 } | |
| 226 | |
| 227 void TouchSelectionController::ActivateInsertion() { | |
| 228 DCHECK(!is_selection_active_); | |
| 229 | |
| 230 if (!insertion_handle_) | |
| 231 insertion_handle_.reset(new TouchHandle(this, TOUCH_HANDLE_CENTER)); | |
| 232 | |
| 233 if (!is_insertion_active_) { | |
| 234 is_insertion_active_ = true; | |
| 235 insertion_handle_->SetEnabled(true); | |
| 236 client_->OnSelectionEvent(INSERTION_SHOWN, GetStartPosition()); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 void TouchSelectionController::DeactivateInsertion() { | |
| 241 if (!is_insertion_active_) | |
| 242 return; | |
| 243 DCHECK(insertion_handle_); | |
| 244 is_insertion_active_ = false; | |
| 245 insertion_handle_->SetEnabled(false); | |
| 246 client_->OnSelectionEvent(INSERTION_CLEARED, gfx::PointF()); | |
| 247 } | |
| 248 | |
| 249 void TouchSelectionController::ActivateSelection() { | |
| 250 DCHECK(!is_insertion_active_); | |
| 251 | |
| 252 if (!start_selection_handle_) | |
| 253 start_selection_handle_.reset(new TouchHandle(this, start_orientation_)); | |
| 254 else | |
| 255 start_selection_handle_->SetOrientation(start_orientation_); | |
| 256 | |
| 257 if (!end_selection_handle_) | |
| 258 end_selection_handle_.reset(new TouchHandle(this, end_orientation_)); | |
| 259 else | |
| 260 end_selection_handle_->SetOrientation(end_orientation_); | |
| 261 | |
| 262 if (!is_selection_active_) { | |
| 263 is_selection_active_ = true; | |
| 264 start_selection_handle_->SetEnabled(true); | |
| 265 end_selection_handle_->SetEnabled(true); | |
| 266 client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition()); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 void TouchSelectionController::DeactivateSelection() { | |
| 271 if (!is_selection_active_) | |
| 272 return; | |
| 273 DCHECK(start_selection_handle_); | |
| 274 DCHECK(end_selection_handle_); | |
| 275 start_selection_handle_->SetEnabled(false); | |
| 276 end_selection_handle_->SetEnabled(false); | |
| 277 is_selection_active_ = false; | |
| 278 client_->OnSelectionEvent(SELECTION_CLEARED, gfx::PointF()); | |
| 279 } | |
| 280 | |
| 281 void TouchSelectionController::ResetCachedValues() { | |
| 282 start_rect_ = gfx::RectF(); | |
| 283 end_rect_ = gfx::RectF(); | |
| 284 start_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 285 end_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 286 start_visible_ = false; | |
| 287 end_visible_ = false; | |
| 288 selection_editable_for_last_update_ = false; | |
| 289 } | |
| 290 | |
| 291 gfx::PointF TouchSelectionController::GetStartPosition() const { | |
| 292 return start_rect_.bottom_left(); | |
| 293 } | |
| 294 | |
| 295 gfx::PointF TouchSelectionController::GetEndPosition() const { | |
| 296 return end_rect_.bottom_left(); | |
| 297 } | |
| 298 | |
| 299 float TouchSelectionController::GetStartLineHeight() const { | |
| 300 return start_rect_.height(); | |
| 301 } | |
| 302 | |
| 303 float TouchSelectionController::GetEndLineHeight() const { | |
| 304 return end_rect_.height(); | |
| 305 } | |
| 306 | |
| 307 TouchHandle::AnimationStyle | |
| 308 TouchSelectionController::GetAnimationStyle() const { | |
| 309 return client_->SupportsAnimation() ? TouchHandle::ANIMATION_SMOOTH | |
| 310 : TouchHandle::ANIMATION_NONE; | |
| 311 } | |
| 312 | |
| 313 } // namespace content | |
| OLD | NEW |