Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: ui/touch_selection/touch_handle.cc

Issue 481683003: Support for Adaptive Handle Orientation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed nits Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/touch_selection/touch_handle.h" 5 #include "ui/touch_selection/touch_handle.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 namespace ui { 9 namespace ui {
10 10
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 return os << "CENTER"; 56 return os << "CENTER";
57 case TouchHandleOrientation::UNDEFINED: 57 case TouchHandleOrientation::UNDEFINED:
58 return os << "UNDEFINED"; 58 return os << "UNDEFINED";
59 default: 59 default:
60 return os << "INVALID: " << static_cast<int>(orientation); 60 return os << "INVALID: " << static_cast<int>(orientation);
61 } 61 }
62 } 62 }
63 63
64 // Responsible for rendering a selection or insertion handle for text editing. 64 // Responsible for rendering a selection or insertion handle for text editing.
65 TouchHandle::TouchHandle(TouchHandleClient* client, 65 TouchHandle::TouchHandle(TouchHandleClient* client,
66 TouchHandleOrientation orientation) 66 TouchHandleOrientation orientation,
67 const gfx::RectF viewport_rect)
67 : drawable_(client->CreateDrawable()), 68 : drawable_(client->CreateDrawable()),
68 client_(client), 69 client_(client),
70 viewport_rect_(viewport_rect),
69 orientation_(orientation), 71 orientation_(orientation),
70 deferred_orientation_(TouchHandleOrientation::UNDEFINED), 72 deferred_orientation_(TouchHandleOrientation::UNDEFINED),
71 alpha_(0.f), 73 alpha_(0.f),
72 animate_deferred_fade_(false), 74 animate_deferred_fade_(false),
73 enabled_(true), 75 enabled_(true),
74 is_visible_(false), 76 is_visible_(false),
75 is_dragging_(false), 77 is_dragging_(false),
76 is_drag_within_tap_region_(false) { 78 is_drag_within_tap_region_(false),
79 is_handle_layout_update_required_(false),
80 mirror_vertical_(false),
81 mirror_horizontal_(false) {
77 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); 82 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED);
78 drawable_->SetEnabled(enabled_); 83 drawable_->SetEnabled(enabled_);
79 drawable_->SetOrientation(orientation_); 84 drawable_->SetOrientation(orientation_, false, false);
85 drawable_->SetOrigin(focus_bottom_);
80 drawable_->SetAlpha(alpha_); 86 drawable_->SetAlpha(alpha_);
81 drawable_->SetFocus(position_); 87 handle_horizontal_padding_ = drawable_->GetDrawableHorizontalPadding();
82 } 88 }
83 89
84 TouchHandle::~TouchHandle() { 90 TouchHandle::~TouchHandle() {
85 } 91 }
86 92
87 void TouchHandle::SetEnabled(bool enabled) { 93 void TouchHandle::SetEnabled(bool enabled) {
88 if (enabled_ == enabled) 94 if (enabled_ == enabled)
89 return; 95 return;
90 if (!enabled) { 96 if (!enabled) {
91 EndDrag(); 97 EndDrag();
92 EndFade(); 98 EndFade();
93 } 99 }
94 enabled_ = enabled; 100 enabled_ = enabled;
95 drawable_->SetEnabled(enabled); 101 drawable_->SetEnabled(enabled);
96 } 102 }
97 103
98 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { 104 void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) {
99 DCHECK(enabled_); 105 DCHECK(enabled_);
100 if (is_visible_ == visible) 106 if (is_visible_ == visible)
101 return; 107 return;
102 108
103 is_visible_ = visible; 109 is_visible_ = visible;
104 110
105 // Handle repositioning may have been deferred while previously invisible. 111 // Handle repositioning may have been deferred while previously invisible.
106 if (visible) 112 SetUpdateLayoutRequired();
mfomitchev 2015/08/06 14:33:02 if (visible) ?
AviD 2015/08/09 13:55:41 There is a visibility check in SetUpdateLayoutRequ
mfomitchev 2015/08/10 13:23:45 Yeah, I realize we check visibility in UpdateHandl
AviD 2015/08/10 14:16:10 Added the visibility check here.
107 drawable_->SetFocus(position_);
108 113
109 bool animate = animation_style != ANIMATION_NONE; 114 bool animate = animation_style != ANIMATION_NONE;
110 if (is_dragging_) { 115 if (is_dragging_) {
111 animate_deferred_fade_ = animate; 116 animate_deferred_fade_ = animate;
112 return; 117 return;
113 } 118 }
114 119
115 if (animate) 120 if (animate)
116 BeginFade(); 121 BeginFade();
117 else 122 else
118 EndFade(); 123 EndFade();
119 } 124 }
120 125
121 void TouchHandle::SetPosition(const gfx::PointF& position) { 126 void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) {
122 DCHECK(enabled_); 127 if (focus_top_ == top && focus_bottom_ == bottom)
123 if (position_ == position)
124 return; 128 return;
125 position_ = position; 129
126 // Suppress repositioning a handle while invisible or fading out to prevent it 130 focus_top_ = top;
127 // from "ghosting" outside the visible bounds. The position will be pushed to 131 focus_bottom_ = bottom;
128 // the drawable when the handle regains visibility (see |SetVisible()|). 132 SetUpdateLayoutRequired();
129 if (is_visible_) 133 }
130 drawable_->SetFocus(position_); 134
135 void TouchHandle::SetViewportRect(const gfx::RectF viewport_rect) {
136 if (viewport_rect_ == viewport_rect)
137 return;
138
139 viewport_rect_ = viewport_rect;
140 SetUpdateLayoutRequired();
131 } 141 }
132 142
133 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { 143 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
134 DCHECK(enabled_); 144 DCHECK(enabled_);
135 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); 145 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED);
136 if (is_dragging_) { 146 if (is_dragging_) {
137 deferred_orientation_ = orientation; 147 deferred_orientation_ = orientation;
138 return; 148 return;
139 } 149 }
140 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); 150 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED);
141 if (orientation_ == orientation) 151 if (orientation_ == orientation)
142 return; 152 return;
143 153
144 orientation_ = orientation; 154 orientation_ = orientation;
145 drawable_->SetOrientation(orientation); 155 SetUpdateLayoutRequired();
146 } 156 }
147 157
148 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { 158 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) {
149 if (!enabled_) 159 if (!enabled_)
150 return false; 160 return false;
151 161
152 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) 162 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN)
153 return false; 163 return false;
154 164
155 switch (event.GetAction()) { 165 switch (event.GetAction()) {
156 case MotionEvent::ACTION_DOWN: { 166 case MotionEvent::ACTION_DOWN: {
157 if (!is_visible_) 167 if (!is_visible_)
158 return false; 168 return false;
159 const gfx::PointF touch_point(event.GetX(), event.GetY()); 169 const gfx::PointF touch_point(event.GetX(), event.GetY());
160 const float touch_radius = std::max( 170 const float touch_radius = std::max(
161 kMinTouchMajorForHitTesting, 171 kMinTouchMajorForHitTesting,
162 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; 172 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f;
163 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(), 173 if (!RectIntersectsCircle(drawable_->GetVisibleBounds(),
164 touch_point, 174 touch_point,
165 touch_radius)) { 175 touch_radius)) {
166 EndDrag(); 176 EndDrag();
167 return false; 177 return false;
168 } 178 }
169 touch_down_position_ = touch_point; 179 touch_down_position_ = touch_point;
170 touch_drag_offset_ = position_ - touch_down_position_; 180 touch_drag_offset_ = focus_bottom_ - touch_down_position_;
171 touch_down_time_ = event.GetEventTime(); 181 touch_down_time_ = event.GetEventTime();
172 BeginDrag(); 182 BeginDrag();
173 } break; 183 } break;
174 184
175 case MotionEvent::ACTION_MOVE: { 185 case MotionEvent::ACTION_MOVE: {
176 gfx::PointF touch_move_position(event.GetX(), event.GetY()); 186 gfx::PointF touch_move_position(event.GetX(), event.GetY());
177 is_drag_within_tap_region_ &= 187 is_drag_within_tap_region_ &=
178 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); 188 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position);
179 189
180 // Note that we signal drag update even if we're inside the tap region, 190 // Note that we signal drag update even if we're inside the tap region,
(...skipping 26 matching lines...) Expand all
207 } 217 }
208 218
209 bool TouchHandle::Animate(base::TimeTicks frame_time) { 219 bool TouchHandle::Animate(base::TimeTicks frame_time) {
210 if (fade_end_time_ == base::TimeTicks()) 220 if (fade_end_time_ == base::TimeTicks())
211 return false; 221 return false;
212 222
213 DCHECK(enabled_); 223 DCHECK(enabled_);
214 224
215 float time_u = 225 float time_u =
216 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; 226 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs;
217 float position_u = 227 float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() /
218 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; 228 kFadeDistanceSquared;
219 float u = std::max(time_u, position_u); 229 float u = std::max(time_u, position_u);
220 SetAlpha(is_visible_ ? u : 1.f - u); 230 SetAlpha(is_visible_ ? u : 1.f - u);
221 231
222 if (u >= 1.f) { 232 if (u >= 1.f) {
223 EndFade(); 233 EndFade();
224 return false; 234 return false;
225 } 235 }
226 236
227 return true; 237 return true;
228 } 238 }
229 239
230 gfx::RectF TouchHandle::GetVisibleBounds() const { 240 gfx::RectF TouchHandle::GetVisibleBounds() const {
231 if (!is_visible_ || !enabled_) 241 if (!is_visible_ || !enabled_)
232 return gfx::RectF(); 242 return gfx::RectF();
233 243
234 return drawable_->GetVisibleBounds(); 244 return drawable_->GetVisibleBounds();
235 } 245 }
236 246
247 gfx::PointF TouchHandle::GetHandleOrigin() const {
248 gfx::PointF position = mirror_vertical_ ? focus_top_ : focus_bottom_;
mfomitchev 2015/08/06 14:33:02 Call this "focus" instead of position? IMO positio
AviD 2015/08/09 13:55:41 Done.
249 gfx::RectF drawable_bounds = drawable_->GetVisibleBounds();
250 float drawable_width = drawable_->GetVisibleBounds().width();
251
252 // Set the Focal offsets for the composited handle layer
mfomitchev 2015/08/06 14:33:02 "focal offsets from origin"?
AviD 2015/08/09 13:55:41 Done.
253 // based on the orientation
254 int focal_offset_x = 0;
255 int focal_offset_y = mirror_vertical_ ? drawable_bounds.height() : 0;
256 switch (orientation_) {
257 case ui::TouchHandleOrientation::LEFT:
258 focal_offset_x =
259 mirror_horizontal_
260 ? drawable_width * handle_horizontal_padding_
261 : drawable_width * (1.0f - handle_horizontal_padding_);
262 break;
263 case ui::TouchHandleOrientation::RIGHT:
264 focal_offset_x =
265 mirror_horizontal_
266 ? drawable_width * (1.0f - handle_horizontal_padding_)
267 : drawable_width * handle_horizontal_padding_;
268 break;
269 case ui::TouchHandleOrientation::CENTER:
270 focal_offset_x = drawable_width * 0.5f;
271 break;
272 case ui::TouchHandleOrientation::UNDEFINED:
273 NOTREACHED() << "Invalid touch handle orientation.";
274 break;
275 };
276
277 gfx::Vector2dF offset_from_origin_ =
mfomitchev 2015/08/06 14:33:02 I'd just remove this variable and use the vector d
AviD 2015/08/09 13:55:41 Done.
278 gfx::Vector2dF(focal_offset_x, focal_offset_y);
279
280 return position - offset_from_origin_;
281 }
282
283 void TouchHandle::UpdateHandleLayout() {
284 // Suppress repositioning a handle while invisible or fading out to prevent it
285 // from "ghosting" outside the visible bounds. The position will be pushed to
286 // the drawable when the handle regains visibility (see |SetVisible()|).
287 if (!is_visible_ || !is_handle_layout_update_required_)
288 return;
289
290 is_handle_layout_update_required_ = false;
291
292 // Update mirror values only when dragging has stopped to prevent unwanted
293 // inversion while dragging of handles
294 if (client_->IsEnabledAdaptiveHandleOrientation() && !is_dragging_) {
295 gfx::RectF handle_bounds = drawable_->GetVisibleBounds();
296 bool mirror_horizontal = false;
297 bool mirror_vertical = false;
298
299 const float handle_width =
300 handle_bounds.width() * (1.0 - handle_horizontal_padding_);
301 const float handle_height = handle_bounds.height();
302
303 const float bottom_y_unmirrored =
304 focus_bottom_.y() + handle_height + viewport_rect_.y();
305 const float top_y_mirrored =
306 focus_top_.y() - handle_height + viewport_rect_.y();
307
308 // In case the viewport height is small, like webview, avoid inversion.
309 if (bottom_y_unmirrored > viewport_rect_.bottom() &&
310 top_y_mirrored > viewport_rect_.y()) {
311 mirror_vertical = true;
312 }
313
314 if (orientation_ == TouchHandleOrientation::LEFT &&
315 focus_bottom_.x() - handle_width < viewport_rect_.x()) {
316 mirror_horizontal = true;
317 } else if (orientation_ == TouchHandleOrientation::RIGHT &&
318 focus_bottom_.x() + handle_width > viewport_rect_.right()) {
319 mirror_horizontal = true;
320 }
321
322 mirror_horizontal_ = mirror_horizontal;
323 mirror_vertical_ = mirror_vertical;
324 }
325
326 drawable_->SetOrientation(orientation_, mirror_vertical_, mirror_horizontal_);
327
328 gfx::PointF origin = GetHandleOrigin();
329 drawable_->SetOrigin(origin);
330 }
331
237 void TouchHandle::BeginDrag() { 332 void TouchHandle::BeginDrag() {
238 DCHECK(enabled_); 333 DCHECK(enabled_);
239 if (is_dragging_) 334 if (is_dragging_)
240 return; 335 return;
241 EndFade(); 336 EndFade();
242 is_dragging_ = true; 337 is_dragging_ = true;
243 is_drag_within_tap_region_ = true; 338 is_drag_within_tap_region_ = true;
244 client_->OnDragBegin(*this, position()); 339 client_->OnDragBegin(*this, focus_bottom());
245 } 340 }
246 341
247 void TouchHandle::EndDrag() { 342 void TouchHandle::EndDrag() {
248 DCHECK(enabled_); 343 DCHECK(enabled_);
249 if (!is_dragging_) 344 if (!is_dragging_)
250 return; 345 return;
251 346
252 is_dragging_ = false; 347 is_dragging_ = false;
253 is_drag_within_tap_region_ = false; 348 is_drag_within_tap_region_ = false;
254 client_->OnDragEnd(*this); 349 client_->OnDragEnd(*this);
255 350
256 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { 351 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) {
257 TouchHandleOrientation deferred_orientation = deferred_orientation_; 352 TouchHandleOrientation deferred_orientation = deferred_orientation_;
258 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; 353 deferred_orientation_ = TouchHandleOrientation::UNDEFINED;
259 SetOrientation(deferred_orientation); 354 SetOrientation(deferred_orientation);
355 // Handle layout may is deferred while the handle is dragged.
356 SetUpdateLayoutRequired();
357 UpdateHandleLayout();
260 } 358 }
261 359
262 if (animate_deferred_fade_) { 360 if (animate_deferred_fade_) {
263 BeginFade(); 361 BeginFade();
264 } else { 362 } else {
265 // As drawable visibility assignment is deferred while dragging, push the 363 // As drawable visibility assignment is deferred while dragging, push the
266 // change by forcing fade completion. 364 // change by forcing fade completion.
267 EndFade(); 365 EndFade();
268 } 366 }
269 } 367 }
270 368
271 void TouchHandle::BeginFade() { 369 void TouchHandle::BeginFade() {
272 DCHECK(enabled_); 370 DCHECK(enabled_);
273 DCHECK(!is_dragging_); 371 DCHECK(!is_dragging_);
274 animate_deferred_fade_ = false; 372 animate_deferred_fade_ = false;
275 const float target_alpha = is_visible_ ? 1.f : 0.f; 373 const float target_alpha = is_visible_ ? 1.f : 0.f;
276 if (target_alpha == alpha_) { 374 if (target_alpha == alpha_) {
277 EndFade(); 375 EndFade();
278 return; 376 return;
279 } 377 }
280 378
281 fade_end_time_ = base::TimeTicks::Now() + 379 fade_end_time_ = base::TimeTicks::Now() +
282 base::TimeDelta::FromMillisecondsD( 380 base::TimeDelta::FromMillisecondsD(
283 kFadeDurationMs * std::abs(target_alpha - alpha_)); 381 kFadeDurationMs * std::abs(target_alpha - alpha_));
284 fade_start_position_ = position_; 382 fade_start_position_ = focus_bottom_;
285 client_->SetNeedsAnimate(); 383 client_->SetNeedsAnimate();
286 } 384 }
287 385
288 void TouchHandle::EndFade() { 386 void TouchHandle::EndFade() {
289 DCHECK(enabled_); 387 DCHECK(enabled_);
290 animate_deferred_fade_ = false; 388 animate_deferred_fade_ = false;
291 fade_end_time_ = base::TimeTicks(); 389 fade_end_time_ = base::TimeTicks();
292 SetAlpha(is_visible_ ? 1.f : 0.f); 390 SetAlpha(is_visible_ ? 1.f : 0.f);
293 } 391 }
294 392
295 void TouchHandle::SetAlpha(float alpha) { 393 void TouchHandle::SetAlpha(float alpha) {
296 alpha = std::max(0.f, std::min(1.f, alpha)); 394 alpha = std::max(0.f, std::min(1.f, alpha));
297 if (alpha_ == alpha) 395 if (alpha_ == alpha)
298 return; 396 return;
299 alpha_ = alpha; 397 alpha_ = alpha;
300 drawable_->SetAlpha(alpha); 398 drawable_->SetAlpha(alpha);
301 } 399 }
302 400
303 } // namespace ui 401 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698