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. | |
|
cjhopman
2014/07/09 22:29:12
Is it possible that I could have selection and the
jdduke (slow)
2014/07/10 02:08:39
Hmm, you're quite right... perhaps we require that
| |
| 64 if (is_selection_dragging) { | |
| 65 if (start_orientation_ == TOUCH_HANDLE_CENTER) | |
| 66 start_orientation_ = start_selection_handle_->orientation(); | |
| 67 if (end_orientation_ == TOUCH_HANDLE_CENTER) | |
| 68 end_orientation_ = end_selection_handle_->orientation(); | |
| 69 } | |
| 70 | |
| 71 const gfx::PointF start = GetStartPosition(); | |
| 72 const gfx::PointF end = GetEndPosition(); | |
| 73 if (start != end || is_selection_dragging) { | |
| 74 OnSelectionChanged(); | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 if (start_orientation_ == TOUCH_HANDLE_CENTER) { | |
| 79 OnInsertionChanged(); | |
| 80 return; | |
| 81 } | |
| 82 | |
| 83 HideAndDisallowAutomaticShowing(); | |
| 84 } | |
| 85 | |
| 86 bool TouchSelectionController::WillHandleTouchEvent( | |
| 87 const ui::MotionEvent& event) { | |
| 88 if (is_insertion_active_) { | |
| 89 DCHECK(insertion_handle_); | |
| 90 return insertion_handle_->WillHandleTouchEvent(event); | |
| 91 } | |
| 92 | |
| 93 if (is_selection_active_) { | |
| 94 DCHECK(start_selection_handle_); | |
| 95 DCHECK(end_selection_handle_); | |
| 96 return start_selection_handle_->WillHandleTouchEvent(event) || | |
| 97 end_selection_handle_->WillHandleTouchEvent(event); | |
| 98 } | |
| 99 | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 void TouchSelectionController::AllowAutomaticInsertionShowing() { | |
| 104 if (allow_automatic_insertion_activation_) | |
| 105 return; | |
| 106 allow_automatic_insertion_activation_ = true; | |
| 107 if (!is_insertion_active_ && !is_selection_active_) | |
| 108 ResetCachedValues(); | |
| 109 } | |
| 110 | |
| 111 void TouchSelectionController::AllowAutomaticSelectionShowing() { | |
| 112 if (allow_automatic_selection_activation_) | |
| 113 return; | |
| 114 allow_automatic_selection_activation_ = true; | |
| 115 if (!is_insertion_active_ && !is_selection_active_) | |
| 116 ResetCachedValues(); | |
| 117 } | |
| 118 | |
| 119 void TouchSelectionController::HideAndDisallowAutomaticShowing() { | |
| 120 DeactivateInsertion(); | |
| 121 DeactivateSelection(); | |
| 122 allow_automatic_insertion_activation_ = false; | |
| 123 allow_automatic_selection_activation_ = false; | |
| 124 } | |
| 125 | |
| 126 void TouchSelectionController::OnSelectionEditable(bool editable) { | |
| 127 if (selection_editable_ == editable) | |
| 128 return; | |
| 129 selection_editable_ = editable; | |
| 130 if (!selection_editable_) | |
| 131 DeactivateInsertion(); | |
| 132 } | |
| 133 | |
| 134 bool TouchSelectionController::Animate(base::TimeTicks frame_time) { | |
| 135 if (is_insertion_active_) | |
| 136 return insertion_handle_->Animate(frame_time); | |
| 137 | |
| 138 if (is_selection_active_) { | |
| 139 bool needs_animate = start_selection_handle_->Animate(frame_time); | |
| 140 needs_animate |= end_selection_handle_->Animate(frame_time); | |
| 141 return needs_animate; | |
| 142 } | |
| 143 | |
| 144 return false; | |
| 145 } | |
| 146 | |
| 147 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { | |
| 148 if (&handle == insertion_handle_.get()) | |
| 149 return; | |
| 150 | |
| 151 if (&handle == start_selection_handle_.get()) { | |
| 152 fixed_handle_position_ = end_selection_handle_->position() - | |
| 153 gfx::Vector2dF(0, GetEndLineHeight() / 2.f); | |
| 154 } else { | |
| 155 fixed_handle_position_ = start_selection_handle_->position() - | |
| 156 gfx::Vector2dF(0, GetStartLineHeight() / 2.f); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, | |
| 161 const gfx::PointF& position) { | |
| 162 // As the position corresponds to the bottom left point of the selection | |
| 163 // bound, offset it by half the corresponding line height. | |
| 164 float half_line_height = &handle == end_selection_handle_.get() | |
| 165 ? GetEndLineHeight() / 2.f | |
| 166 : GetStartLineHeight() / 2.f; | |
| 167 gfx::PointF line_position = position - gfx::Vector2dF(0, half_line_height); | |
| 168 if (&handle == insertion_handle_.get()) { | |
| 169 client_->MoveCaret(line_position); | |
| 170 } else { | |
| 171 client_->SelectBetweenCoordinates(fixed_handle_position_, line_position); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) { | |
| 176 } | |
| 177 | |
| 178 void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) { | |
| 179 if (insertion_handle_ && &handle == insertion_handle_.get()) | |
| 180 client_->OnSelectionEvent(INSERTION_TAPPED, GetStartPosition()); | |
| 181 } | |
| 182 | |
| 183 void TouchSelectionController::SetNeedsAnimate() { | |
| 184 client_->SetNeedsAnimate(); | |
| 185 } | |
| 186 | |
| 187 scoped_ptr<TouchHandleDrawable> TouchSelectionController::CreateDrawable() { | |
| 188 return client_->CreateDrawable(); | |
| 189 } | |
| 190 | |
| 191 void TouchSelectionController::OnInsertionChanged() { | |
| 192 DeactivateSelection(); | |
| 193 | |
| 194 if (!allow_automatic_insertion_activation_ || !selection_editable_) | |
| 195 return; | |
| 196 | |
| 197 bool was_active = is_insertion_active_; | |
| 198 gfx::PointF position = GetStartPosition(); | |
| 199 if (!was_active) | |
| 200 ActivateInsertion(); | |
| 201 else | |
| 202 client_->OnSelectionEvent(INSERTION_MOVED, position); | |
| 203 | |
| 204 insertion_handle_->SetVisible( | |
| 205 start_visible_, | |
| 206 was_active ? TouchHandle::ANIMATION_SMOOTH : TouchHandle::ANIMATION_NONE); | |
| 207 | |
| 208 insertion_handle_->SetPosition(position); | |
| 209 } | |
| 210 | |
| 211 void TouchSelectionController::OnSelectionChanged() { | |
| 212 DeactivateInsertion(); | |
| 213 | |
| 214 if (!allow_automatic_selection_activation_) | |
| 215 return; | |
| 216 | |
| 217 const bool was_active = is_selection_active_; | |
| 218 ActivateSelection(); | |
| 219 | |
| 220 const TouchHandle::AnimationStyle animation = | |
| 221 was_active ? TouchHandle::ANIMATION_SMOOTH : TouchHandle::ANIMATION_NONE; | |
| 222 start_selection_handle_->SetVisible(start_visible_, animation); | |
| 223 end_selection_handle_->SetVisible(end_visible_, animation); | |
| 224 | |
| 225 start_selection_handle_->SetPosition(GetStartPosition()); | |
| 226 end_selection_handle_->SetPosition(GetEndPosition()); | |
| 227 } | |
| 228 | |
| 229 void TouchSelectionController::ActivateInsertion() { | |
| 230 DCHECK(!is_selection_active_); | |
| 231 | |
| 232 if (!insertion_handle_) | |
| 233 insertion_handle_.reset(new TouchHandle(this, TOUCH_HANDLE_CENTER)); | |
| 234 | |
| 235 if (!is_insertion_active_) { | |
| 236 is_insertion_active_ = true; | |
| 237 client_->OnSelectionEvent(INSERTION_SHOWN, GetStartPosition()); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 void TouchSelectionController::DeactivateInsertion() { | |
| 242 if (!is_insertion_active_) | |
| 243 return; | |
| 244 DCHECK(insertion_handle_); | |
| 245 insertion_handle_->Hide(); | |
| 246 is_insertion_active_ = false; | |
| 247 client_->OnSelectionEvent(INSERTION_CLEARED, gfx::PointF()); | |
| 248 } | |
| 249 | |
| 250 void TouchSelectionController::ActivateSelection() { | |
| 251 DCHECK(!is_insertion_active_); | |
| 252 | |
| 253 if (!start_selection_handle_) | |
| 254 start_selection_handle_.reset(new TouchHandle(this, start_orientation_)); | |
| 255 else | |
| 256 start_selection_handle_->SetOrientation(start_orientation_); | |
| 257 | |
| 258 if (!end_selection_handle_) | |
| 259 end_selection_handle_.reset(new TouchHandle(this, end_orientation_)); | |
| 260 else | |
| 261 end_selection_handle_->SetOrientation(end_orientation_); | |
| 262 | |
| 263 if (!is_selection_active_) { | |
| 264 is_selection_active_ = true; | |
| 265 client_->OnSelectionEvent(SELECTION_SHOWN, GetStartPosition()); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 void TouchSelectionController::DeactivateSelection() { | |
| 270 if (!is_selection_active_) | |
| 271 return; | |
| 272 DCHECK(start_selection_handle_); | |
| 273 DCHECK(end_selection_handle_); | |
| 274 start_selection_handle_->Hide(); | |
| 275 end_selection_handle_->Hide(); | |
| 276 is_selection_active_ = false; | |
| 277 client_->OnSelectionEvent(SELECTION_CLEARED, gfx::PointF()); | |
| 278 } | |
| 279 | |
| 280 void TouchSelectionController::ResetCachedValues() { | |
| 281 start_rect_ = gfx::RectF(); | |
| 282 end_rect_ = gfx::RectF(); | |
| 283 start_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 284 end_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 285 start_visible_ = false; | |
| 286 end_visible_ = false; | |
| 287 selection_editable_for_last_update_ = false; | |
| 288 } | |
| 289 | |
| 290 gfx::PointF TouchSelectionController::GetStartPosition() const { | |
| 291 return start_rect_.bottom_left(); | |
| 292 } | |
| 293 | |
| 294 gfx::PointF TouchSelectionController::GetEndPosition() const { | |
| 295 return end_rect_.bottom_left(); | |
| 296 } | |
| 297 | |
| 298 float TouchSelectionController::GetStartLineHeight() const { | |
| 299 return start_rect_.height(); | |
| 300 } | |
| 301 | |
| 302 float TouchSelectionController::GetEndLineHeight() const { | |
| 303 return end_rect_.height(); | |
| 304 } | |
| 305 | |
| 306 } // namespace content | |
| OLD | NEW |