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 |