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 |