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 | |
| 9 namespace content { | |
| 10 | |
| 11 TouchSelectionController::TouchSelectionController( | |
| 12 TouchSelectionControllerClient* client) | |
| 13 : client_(client), | |
| 14 anchor_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | |
| 15 anchor_visible_(false), | |
| 16 focus_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED), | |
| 17 focus_visible_(false), | |
| 18 is_insertion_active_(false), | |
| 19 allow_automatic_insertion_activation_(false), | |
| 20 is_selection_active_(false), | |
| 21 allow_automatic_selection_activation_(false), | |
| 22 selection_editable_(false), | |
| 23 selection_editable_for_last_update_(false) { | |
| 24 DCHECK(client_); | |
| 25 HideAndDisallowAutomaticShowing(); | |
| 26 } | |
| 27 | |
| 28 TouchSelectionController::~TouchSelectionController() { | |
| 29 } | |
| 30 | |
| 31 void TouchSelectionController::OnSelectionBoundsChanged( | |
| 32 const gfx::RectF& anchor_rect, | |
| 33 TouchHandleOrientation anchor_orientation, | |
| 34 bool anchor_visible, | |
| 35 const gfx::RectF& focus_rect, | |
| 36 TouchHandleOrientation focus_orientation, | |
| 37 bool focus_visible) { | |
| 38 if (!allow_automatic_selection_activation_ && | |
| 39 !allow_automatic_insertion_activation_) | |
| 40 return; | |
| 41 | |
| 42 if (anchor_rect_ == anchor_rect && focus_rect_ == focus_rect && | |
| 43 anchor_orientation_ == anchor_orientation && | |
| 44 focus_orientation_ == focus_orientation && | |
| 45 anchor_visible_ == anchor_visible && focus_visible_ == focus_visible && | |
| 46 selection_editable_ == selection_editable_for_last_update_) | |
| 47 return; | |
| 48 | |
| 49 anchor_rect_ = anchor_rect; | |
| 50 anchor_orientation_ = anchor_orientation; | |
| 51 anchor_visible_ = anchor_visible; | |
| 52 focus_rect_ = focus_rect; | |
| 53 focus_orientation_ = focus_orientation; | |
| 54 focus_visible_ = focus_visible; | |
| 55 selection_editable_for_last_update_ = selection_editable_; | |
| 56 | |
| 57 const gfx::PointF anchor = GetAnchorPosition(); | |
| 58 const gfx::PointF focus = GetFocusPosition(); | |
| 59 if (anchor.x() != focus.x() || anchor.y() != focus.y() || | |
|
cjhopman
2014/07/07 22:13:41
anchor != focus
jdduke (slow)
2014/07/08 00:54:44
Done.
| |
| 60 (start_selection_handle_ && start_selection_handle_->is_dragging()) || | |
|
cjhopman
2014/07/07 22:13:41
Can this just use is_selection_active_ rather than
jdduke (slow)
2014/07/08 00:54:44
Done.
| |
| 61 (end_selection_handle_ && end_selection_handle_->is_dragging())) { | |
| 62 // It's possible that the bounds temporarily overlap while a handle is | |
| 63 // being dragged, incorrectly reporting a CENTER orientation. | |
| 64 if (anchor_orientation_ == TOUCH_HANDLE_CENTER && start_selection_handle_) | |
|
cjhopman
2014/07/07 22:13:41
AIUI, if anchor_orientation_ == TOUCH_HANDLE_CENTE
jdduke (slow)
2014/07/08 00:54:44
It's definitely better, good call.
| |
| 65 anchor_orientation_ = start_selection_handle_->orientation(); | |
| 66 if (focus_orientation_ == TOUCH_HANDLE_CENTER && end_selection_handle_) | |
| 67 focus_orientation_ = end_selection_handle_->orientation(); | |
| 68 | |
| 69 OnSelectionChanged(); | |
| 70 return; | |
| 71 } | |
| 72 | |
| 73 if (anchor_orientation_ == TOUCH_HANDLE_CENTER) { | |
| 74 OnInsertionChanged(); | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 HideAndDisallowAutomaticShowing(); | |
| 79 } | |
| 80 | |
| 81 bool TouchSelectionController::WillHandleTouchEvent( | |
| 82 const ui::MotionEvent& event) { | |
| 83 if (is_insertion_active_) { | |
| 84 DCHECK(insertion_handle_); | |
| 85 return insertion_handle_->WillHandleTouchEvent(event); | |
| 86 } | |
| 87 | |
| 88 if (is_selection_active_) { | |
| 89 DCHECK(start_selection_handle_); | |
| 90 DCHECK(end_selection_handle_); | |
| 91 return start_selection_handle_->WillHandleTouchEvent(event) || | |
| 92 end_selection_handle_->WillHandleTouchEvent(event); | |
| 93 } | |
| 94 | |
| 95 return false; | |
| 96 } | |
| 97 | |
| 98 void TouchSelectionController::AllowAutomaticInsertionShowing() { | |
| 99 if (allow_automatic_insertion_activation_) | |
| 100 return; | |
| 101 allow_automatic_insertion_activation_ = true; | |
| 102 if (!is_insertion_active_ && !is_selection_active_) | |
| 103 ResetCachedValues(); | |
| 104 } | |
| 105 | |
| 106 void TouchSelectionController::AllowAutomaticSelectionShowing() { | |
| 107 if (allow_automatic_selection_activation_) | |
| 108 return; | |
| 109 allow_automatic_selection_activation_ = true; | |
| 110 if (!is_insertion_active_ && !is_selection_active_) | |
| 111 ResetCachedValues(); | |
| 112 } | |
| 113 | |
| 114 void TouchSelectionController::HideAndDisallowAutomaticShowing() { | |
| 115 DeactivateInsertion(); | |
| 116 DeactivateSelection(); | |
| 117 allow_automatic_insertion_activation_ = false; | |
| 118 allow_automatic_selection_activation_ = false; | |
| 119 } | |
| 120 | |
| 121 void TouchSelectionController::OnSelectionEditable(bool editable) { | |
| 122 if (selection_editable_ == editable) | |
| 123 return; | |
| 124 selection_editable_ = editable; | |
| 125 if (!selection_editable_) | |
| 126 DeactivateInsertion(); | |
| 127 } | |
| 128 | |
| 129 bool TouchSelectionController::Animate(base::TimeTicks frame_time) { | |
| 130 if (is_insertion_active_) | |
| 131 return insertion_handle_->Animate(frame_time); | |
| 132 | |
| 133 if (is_selection_active_) { | |
| 134 bool needs_animate = start_selection_handle_->Animate(frame_time); | |
| 135 needs_animate |= end_selection_handle_->Animate(frame_time); | |
| 136 return needs_animate; | |
| 137 } | |
| 138 | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 void TouchSelectionController::OnHandleDragBegin(const TouchHandle& handle) { | |
| 143 if (&handle == insertion_handle_.get()) | |
| 144 return; | |
| 145 | |
| 146 if (&handle == start_selection_handle_.get()) { | |
| 147 fixed_handle_position_ = end_selection_handle_->position() - | |
| 148 gfx::Vector2dF(0, GetFocusLineHeight() / 2.f); | |
| 149 } else { | |
| 150 fixed_handle_position_ = start_selection_handle_->position() - | |
| 151 gfx::Vector2dF(0, GetAnchorLineHeight() / 2.f); | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 void TouchSelectionController::OnHandleDragUpdate(const TouchHandle& handle, | |
| 156 const gfx::PointF& position) { | |
| 157 // As the position corresponds to the bottom left point of the selection | |
| 158 // bound, offset it by half the corresponding line height. | |
| 159 float half_line_height = &handle == end_selection_handle_.get() | |
| 160 ? GetFocusLineHeight() / 2.f | |
| 161 : GetAnchorLineHeight() / 2.f; | |
| 162 gfx::PointF line_position = position - gfx::Vector2dF(0, half_line_height); | |
| 163 if (&handle == insertion_handle_.get()) { | |
| 164 client_->MoveCaret(line_position); | |
| 165 } else { | |
| 166 client_->SelectBetweenCoordinates(fixed_handle_position_, line_position); | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 void TouchSelectionController::OnHandleDragEnd(const TouchHandle& handle) { | |
| 171 } | |
| 172 | |
| 173 void TouchSelectionController::OnHandleTapped(const TouchHandle& handle) { | |
| 174 if (insertion_handle_ && &handle == insertion_handle_.get()) | |
| 175 client_->OnSelectionEvent(INSERTION_TAPPED, GetAnchorPosition()); | |
| 176 } | |
| 177 | |
| 178 void TouchSelectionController::SetNeedsAnimate() { | |
| 179 client_->SetNeedsAnimate(); | |
| 180 } | |
| 181 | |
| 182 scoped_ptr<TouchHandleDrawable> TouchSelectionController::CreateDrawable() { | |
| 183 return client_->CreateDrawable(); | |
| 184 } | |
| 185 | |
| 186 void TouchSelectionController::OnInsertionChanged() { | |
| 187 DeactivateSelection(); | |
| 188 | |
| 189 if (!allow_automatic_insertion_activation_ || !selection_editable_) | |
| 190 return; | |
| 191 | |
| 192 bool was_active = is_insertion_active_; | |
| 193 gfx::PointF position = GetAnchorPosition(); | |
| 194 if (!was_active) | |
| 195 ActivateInsertion(); | |
| 196 else | |
| 197 client_->OnSelectionEvent(INSERTION_MOVED, position); | |
| 198 | |
| 199 if (was_active) | |
| 200 insertion_handle_->SetVisibleAnimated(anchor_visible_); | |
| 201 else | |
| 202 insertion_handle_->SetVisible(anchor_visible_); | |
| 203 | |
| 204 insertion_handle_->SetPosition(position); | |
| 205 } | |
| 206 | |
| 207 void TouchSelectionController::OnSelectionChanged() { | |
| 208 DeactivateInsertion(); | |
| 209 | |
| 210 if (!allow_automatic_selection_activation_) | |
| 211 return; | |
| 212 | |
| 213 const bool was_active = is_selection_active_; | |
| 214 ActivateSelection(); | |
| 215 if (was_active) { | |
| 216 start_selection_handle_->SetVisibleAnimated(anchor_visible_); | |
| 217 end_selection_handle_->SetVisibleAnimated(focus_visible_); | |
| 218 } else { | |
| 219 start_selection_handle_->SetVisible(anchor_visible_); | |
| 220 end_selection_handle_->SetVisible(focus_visible_); | |
| 221 } | |
| 222 start_selection_handle_->SetPosition(GetAnchorPosition()); | |
| 223 end_selection_handle_->SetPosition(GetFocusPosition()); | |
| 224 } | |
| 225 | |
| 226 void TouchSelectionController::ActivateInsertion() { | |
| 227 DCHECK(!is_selection_active_); | |
| 228 | |
| 229 if (!insertion_handle_) | |
| 230 insertion_handle_.reset(new TouchHandle(this, TOUCH_HANDLE_CENTER)); | |
| 231 | |
| 232 if (!is_insertion_active_) { | |
| 233 is_insertion_active_ = true; | |
| 234 client_->OnSelectionEvent(INSERTION_SHOWN, GetAnchorPosition()); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 void TouchSelectionController::DeactivateInsertion() { | |
| 239 if (!is_insertion_active_) | |
| 240 return; | |
| 241 DCHECK(insertion_handle_); | |
| 242 insertion_handle_->Hide(); | |
| 243 is_insertion_active_ = false; | |
| 244 client_->OnSelectionEvent(INSERTION_CLEARED, gfx::PointF()); | |
| 245 } | |
| 246 | |
| 247 void TouchSelectionController::ActivateSelection() { | |
| 248 DCHECK(!is_insertion_active_); | |
| 249 | |
| 250 if (!start_selection_handle_) | |
| 251 start_selection_handle_.reset(new TouchHandle(this, anchor_orientation_)); | |
| 252 else | |
| 253 start_selection_handle_->SetOrientation(anchor_orientation_); | |
| 254 | |
| 255 if (!end_selection_handle_) | |
| 256 end_selection_handle_.reset(new TouchHandle(this, focus_orientation_)); | |
| 257 else | |
| 258 end_selection_handle_->SetOrientation(focus_orientation_); | |
| 259 | |
| 260 if (!is_selection_active_) { | |
| 261 is_selection_active_ = true; | |
| 262 client_->OnSelectionEvent(SELECTION_SHOWN, GetAnchorPosition()); | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 void TouchSelectionController::DeactivateSelection() { | |
| 267 if (!is_selection_active_) | |
| 268 return; | |
| 269 DCHECK(start_selection_handle_); | |
| 270 DCHECK(end_selection_handle_); | |
| 271 start_selection_handle_->Hide(); | |
| 272 end_selection_handle_->Hide(); | |
| 273 is_selection_active_ = false; | |
| 274 client_->OnSelectionEvent(SELECTION_CLEARED, gfx::PointF()); | |
| 275 } | |
| 276 | |
| 277 void TouchSelectionController::ResetCachedValues() { | |
| 278 anchor_rect_ = gfx::RectF(); | |
| 279 focus_rect_ = gfx::RectF(); | |
| 280 anchor_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 281 focus_orientation_ = TOUCH_HANDLE_ORIENTATION_UNDEFINED; | |
| 282 anchor_visible_ = false; | |
| 283 focus_visible_ = false; | |
| 284 selection_editable_for_last_update_ = false; | |
| 285 } | |
| 286 | |
| 287 gfx::PointF TouchSelectionController::GetAnchorPosition() const { | |
| 288 return anchor_rect_.bottom_left(); | |
| 289 } | |
| 290 | |
| 291 gfx::PointF TouchSelectionController::GetFocusPosition() const { | |
| 292 return focus_rect_.bottom_left(); | |
| 293 } | |
| 294 | |
| 295 float TouchSelectionController::GetAnchorLineHeight() const { | |
| 296 return anchor_rect_.height(); | |
| 297 } | |
| 298 | |
| 299 float TouchSelectionController::GetFocusLineHeight() const { | |
| 300 return focus_rect_.height(); | |
| 301 } | |
| 302 | |
| 303 } // namespace content | |
| OLD | NEW |