Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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_->GetDrawableHorizontalPaddingRatio(); |
| 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 if (visible) |
| 107 drawable_->SetFocus(position_); | 113 SetUpdateLayoutRequired(); |
| 108 | 114 |
| 109 bool animate = animation_style != ANIMATION_NONE; | 115 bool animate = animation_style != ANIMATION_NONE; |
| 110 if (is_dragging_) { | 116 if (is_dragging_) { |
| 111 animate_deferred_fade_ = animate; | 117 animate_deferred_fade_ = animate; |
| 112 return; | 118 return; |
| 113 } | 119 } |
| 114 | 120 |
| 115 if (animate) | 121 if (animate) |
| 116 BeginFade(); | 122 BeginFade(); |
| 117 else | 123 else |
| 118 EndFade(); | 124 EndFade(); |
| 119 } | 125 } |
| 120 | 126 |
| 121 void TouchHandle::SetPosition(const gfx::PointF& position) { | 127 void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) { |
| 122 DCHECK(enabled_); | 128 if (focus_top_ == top && focus_bottom_ == bottom) |
|
jdduke (slow)
2015/09/14 15:19:40
Don't we want to keep the DCHECK(enabled_)?
AviD
2015/09/14 15:57:40
Added DCHECK for SetFocus and SetViewportRect as w
| |
| 123 if (position_ == position) | |
| 124 return; | 129 return; |
| 125 position_ = position; | 130 |
| 126 // Suppress repositioning a handle while invisible or fading out to prevent it | 131 focus_top_ = top; |
| 127 // from "ghosting" outside the visible bounds. The position will be pushed to | 132 focus_bottom_ = bottom; |
| 128 // the drawable when the handle regains visibility (see |SetVisible()|). | 133 SetUpdateLayoutRequired(); |
| 129 if (is_visible_) | 134 } |
| 130 drawable_->SetFocus(position_); | 135 |
| 136 void TouchHandle::SetViewportRect(const gfx::RectF& viewport_rect) { | |
| 137 if (viewport_rect_ == viewport_rect) | |
| 138 return; | |
| 139 | |
| 140 viewport_rect_ = viewport_rect; | |
| 141 SetUpdateLayoutRequired(); | |
| 131 } | 142 } |
| 132 | 143 |
| 133 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { | 144 void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { |
| 134 DCHECK(enabled_); | 145 DCHECK(enabled_); |
| 135 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); | 146 DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); |
| 136 if (is_dragging_) { | 147 if (is_dragging_) { |
| 137 deferred_orientation_ = orientation; | 148 deferred_orientation_ = orientation; |
| 138 return; | 149 return; |
| 139 } | 150 } |
| 140 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); | 151 DCHECK_EQ(deferred_orientation_, TouchHandleOrientation::UNDEFINED); |
| 141 if (orientation_ == orientation) | 152 if (orientation_ == orientation) |
| 142 return; | 153 return; |
| 143 | 154 |
| 144 orientation_ = orientation; | 155 orientation_ = orientation; |
| 145 drawable_->SetOrientation(orientation); | 156 SetUpdateLayoutRequired(); |
| 146 } | 157 } |
| 147 | 158 |
| 148 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { | 159 bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { |
| 149 if (!enabled_) | 160 if (!enabled_) |
| 150 return false; | 161 return false; |
| 151 | 162 |
| 152 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) | 163 if (!is_dragging_ && event.GetAction() != MotionEvent::ACTION_DOWN) |
| 153 return false; | 164 return false; |
| 154 | 165 |
| 155 switch (event.GetAction()) { | 166 switch (event.GetAction()) { |
| 156 case MotionEvent::ACTION_DOWN: { | 167 case MotionEvent::ACTION_DOWN: { |
| 157 if (!is_visible_) | 168 if (!is_visible_) |
| 158 return false; | 169 return false; |
| 159 const gfx::PointF touch_point(event.GetX(), event.GetY()); | 170 const gfx::PointF touch_point(event.GetX(), event.GetY()); |
| 160 const float touch_radius = std::max( | 171 const float touch_radius = std::max( |
| 161 kMinTouchMajorForHitTesting, | 172 kMinTouchMajorForHitTesting, |
| 162 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; | 173 std::min(kMaxTouchMajorForHitTesting, event.GetTouchMajor())) * 0.5f; |
| 163 const gfx::RectF drawable_bounds = drawable_->GetVisibleBounds(); | 174 const gfx::RectF drawable_bounds = drawable_->GetVisibleBounds(); |
| 164 // Only use the touch radius for targetting if the touch is at or below | 175 // Only use the touch radius for targetting if the touch is at or below |
| 165 // the drawable area. This makes it easier to interact with the line of | 176 // the drawable area. This makes it easier to interact with the line of |
| 166 // text above the drawable. | 177 // text above the drawable. |
| 167 if (touch_point.y() < drawable_bounds.y() || | 178 if (touch_point.y() < drawable_bounds.y() || |
| 168 !RectIntersectsCircle(drawable_bounds, touch_point, touch_radius)) { | 179 !RectIntersectsCircle(drawable_bounds, touch_point, touch_radius)) { |
| 169 EndDrag(); | 180 EndDrag(); |
| 170 return false; | 181 return false; |
| 171 } | 182 } |
| 172 touch_down_position_ = touch_point; | 183 touch_down_position_ = touch_point; |
| 173 touch_drag_offset_ = position_ - touch_down_position_; | 184 touch_drag_offset_ = focus_bottom_ - touch_down_position_; |
| 174 touch_down_time_ = event.GetEventTime(); | 185 touch_down_time_ = event.GetEventTime(); |
| 175 BeginDrag(); | 186 BeginDrag(); |
| 176 } break; | 187 } break; |
| 177 | 188 |
| 178 case MotionEvent::ACTION_MOVE: { | 189 case MotionEvent::ACTION_MOVE: { |
| 179 gfx::PointF touch_move_position(event.GetX(), event.GetY()); | 190 gfx::PointF touch_move_position(event.GetX(), event.GetY()); |
| 180 is_drag_within_tap_region_ &= | 191 is_drag_within_tap_region_ &= |
| 181 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); | 192 client_->IsWithinTapSlop(touch_down_position_ - touch_move_position); |
| 182 | 193 |
| 183 // Note that we signal drag update even if we're inside the tap region, | 194 // Note that we signal drag update even if we're inside the tap region, |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 210 } | 221 } |
| 211 | 222 |
| 212 bool TouchHandle::Animate(base::TimeTicks frame_time) { | 223 bool TouchHandle::Animate(base::TimeTicks frame_time) { |
| 213 if (fade_end_time_ == base::TimeTicks()) | 224 if (fade_end_time_ == base::TimeTicks()) |
| 214 return false; | 225 return false; |
| 215 | 226 |
| 216 DCHECK(enabled_); | 227 DCHECK(enabled_); |
| 217 | 228 |
| 218 float time_u = | 229 float time_u = |
| 219 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; | 230 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; |
| 220 float position_u = | 231 float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() / |
| 221 (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; | 232 kFadeDistanceSquared; |
| 222 float u = std::max(time_u, position_u); | 233 float u = std::max(time_u, position_u); |
| 223 SetAlpha(is_visible_ ? u : 1.f - u); | 234 SetAlpha(is_visible_ ? u : 1.f - u); |
| 224 | 235 |
| 225 if (u >= 1.f) { | 236 if (u >= 1.f) { |
| 226 EndFade(); | 237 EndFade(); |
| 227 return false; | 238 return false; |
| 228 } | 239 } |
| 229 | 240 |
| 230 return true; | 241 return true; |
| 231 } | 242 } |
| 232 | 243 |
| 233 gfx::RectF TouchHandle::GetVisibleBounds() const { | 244 gfx::RectF TouchHandle::GetVisibleBounds() const { |
| 234 if (!is_visible_ || !enabled_) | 245 if (!is_visible_ || !enabled_) |
| 235 return gfx::RectF(); | 246 return gfx::RectF(); |
| 236 | 247 |
| 237 return drawable_->GetVisibleBounds(); | 248 return drawable_->GetVisibleBounds(); |
| 238 } | 249 } |
| 239 | 250 |
| 251 void TouchHandle::UpdateHandleLayout() { | |
| 252 // Suppress repositioning a handle while invisible or fading out to prevent it | |
| 253 // from "ghosting" outside the visible bounds. The position will be pushed to | |
| 254 // the drawable when the handle regains visibility (see |SetVisible()|). | |
| 255 if (!is_visible_ || !is_handle_layout_update_required_) | |
| 256 return; | |
| 257 | |
| 258 is_handle_layout_update_required_ = false; | |
| 259 | |
| 260 // Update mirror values only when dragging has stopped to prevent unwanted | |
| 261 // inversion while dragging of handles. | |
| 262 if (client_->IsAdaptiveHandleOrientationEnabled() && !is_dragging_) { | |
| 263 gfx::RectF handle_bounds = drawable_->GetVisibleBounds(); | |
| 264 bool mirror_horizontal = false; | |
| 265 bool mirror_vertical = false; | |
| 266 | |
| 267 const float handle_width = | |
| 268 handle_bounds.width() * (1.0 - handle_horizontal_padding_); | |
| 269 const float handle_height = handle_bounds.height(); | |
| 270 | |
| 271 const float bottom_y_unmirrored = | |
| 272 focus_bottom_.y() + handle_height + viewport_rect_.y(); | |
| 273 const float top_y_mirrored = | |
| 274 focus_top_.y() - handle_height + viewport_rect_.y(); | |
| 275 | |
| 276 // In case the viewport height is small, like webview, avoid inversion. | |
| 277 if (bottom_y_unmirrored > viewport_rect_.bottom() && | |
| 278 top_y_mirrored > viewport_rect_.y()) { | |
| 279 mirror_vertical = true; | |
| 280 } | |
| 281 | |
| 282 if (orientation_ == TouchHandleOrientation::LEFT && | |
| 283 focus_bottom_.x() - handle_width < viewport_rect_.x()) { | |
| 284 mirror_horizontal = true; | |
| 285 } else if (orientation_ == TouchHandleOrientation::RIGHT && | |
| 286 focus_bottom_.x() + handle_width > viewport_rect_.right()) { | |
| 287 mirror_horizontal = true; | |
| 288 } | |
| 289 | |
| 290 mirror_horizontal_ = mirror_horizontal; | |
| 291 mirror_vertical_ = mirror_vertical; | |
| 292 } | |
| 293 | |
| 294 drawable_->SetOrientation(orientation_, mirror_vertical_, mirror_horizontal_); | |
| 295 drawable_->SetOrigin(ComputeHandleOrigin()); | |
| 296 } | |
| 297 | |
| 298 gfx::PointF TouchHandle::ComputeHandleOrigin() const { | |
| 299 gfx::PointF focus = mirror_vertical_ ? focus_top_ : focus_bottom_; | |
| 300 gfx::RectF drawable_bounds = drawable_->GetVisibleBounds(); | |
| 301 float drawable_width = drawable_->GetVisibleBounds().width(); | |
| 302 | |
| 303 // Calculate the focal offsets from origin for the handle drawable | |
| 304 // based on the orientation. | |
| 305 int focal_offset_x = 0; | |
| 306 int focal_offset_y = mirror_vertical_ ? drawable_bounds.height() : 0; | |
| 307 switch (orientation_) { | |
| 308 case ui::TouchHandleOrientation::LEFT: | |
| 309 focal_offset_x = | |
| 310 mirror_horizontal_ | |
| 311 ? drawable_width * handle_horizontal_padding_ | |
| 312 : drawable_width * (1.0f - handle_horizontal_padding_); | |
| 313 break; | |
| 314 case ui::TouchHandleOrientation::RIGHT: | |
| 315 focal_offset_x = | |
| 316 mirror_horizontal_ | |
| 317 ? drawable_width * (1.0f - handle_horizontal_padding_) | |
| 318 : drawable_width * handle_horizontal_padding_; | |
| 319 break; | |
| 320 case ui::TouchHandleOrientation::CENTER: | |
| 321 focal_offset_x = drawable_width * 0.5f; | |
| 322 break; | |
| 323 case ui::TouchHandleOrientation::UNDEFINED: | |
| 324 NOTREACHED() << "Invalid touch handle orientation."; | |
| 325 break; | |
| 326 }; | |
| 327 | |
| 328 return focus - gfx::Vector2dF(focal_offset_x, focal_offset_y); | |
| 329 } | |
| 330 | |
| 240 void TouchHandle::BeginDrag() { | 331 void TouchHandle::BeginDrag() { |
| 241 DCHECK(enabled_); | 332 DCHECK(enabled_); |
| 242 if (is_dragging_) | 333 if (is_dragging_) |
| 243 return; | 334 return; |
| 244 EndFade(); | 335 EndFade(); |
| 245 is_dragging_ = true; | 336 is_dragging_ = true; |
| 246 is_drag_within_tap_region_ = true; | 337 is_drag_within_tap_region_ = true; |
| 247 client_->OnDragBegin(*this, position()); | 338 client_->OnDragBegin(*this, focus_bottom()); |
| 248 } | 339 } |
| 249 | 340 |
| 250 void TouchHandle::EndDrag() { | 341 void TouchHandle::EndDrag() { |
| 251 DCHECK(enabled_); | 342 DCHECK(enabled_); |
| 252 if (!is_dragging_) | 343 if (!is_dragging_) |
| 253 return; | 344 return; |
| 254 | 345 |
| 255 is_dragging_ = false; | 346 is_dragging_ = false; |
| 256 is_drag_within_tap_region_ = false; | 347 is_drag_within_tap_region_ = false; |
| 257 client_->OnDragEnd(*this); | 348 client_->OnDragEnd(*this); |
| 258 | 349 |
| 259 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { | 350 if (deferred_orientation_ != TouchHandleOrientation::UNDEFINED) { |
| 260 TouchHandleOrientation deferred_orientation = deferred_orientation_; | 351 TouchHandleOrientation deferred_orientation = deferred_orientation_; |
| 261 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; | 352 deferred_orientation_ = TouchHandleOrientation::UNDEFINED; |
| 262 SetOrientation(deferred_orientation); | 353 SetOrientation(deferred_orientation); |
| 354 // Handle layout may is deferred while the handle is dragged. | |
|
jdduke (slow)
2015/09/14 15:19:40
Nit: "may be deferred".
AviD
2015/09/14 15:57:40
Done.
| |
| 355 SetUpdateLayoutRequired(); | |
| 356 UpdateHandleLayout(); | |
| 263 } | 357 } |
| 264 | 358 |
| 265 if (animate_deferred_fade_) { | 359 if (animate_deferred_fade_) { |
| 266 BeginFade(); | 360 BeginFade(); |
| 267 } else { | 361 } else { |
| 268 // As drawable visibility assignment is deferred while dragging, push the | 362 // As drawable visibility assignment is deferred while dragging, push the |
| 269 // change by forcing fade completion. | 363 // change by forcing fade completion. |
| 270 EndFade(); | 364 EndFade(); |
| 271 } | 365 } |
| 272 } | 366 } |
| 273 | 367 |
| 274 void TouchHandle::BeginFade() { | 368 void TouchHandle::BeginFade() { |
| 275 DCHECK(enabled_); | 369 DCHECK(enabled_); |
| 276 DCHECK(!is_dragging_); | 370 DCHECK(!is_dragging_); |
| 277 animate_deferred_fade_ = false; | 371 animate_deferred_fade_ = false; |
| 278 const float target_alpha = is_visible_ ? 1.f : 0.f; | 372 const float target_alpha = is_visible_ ? 1.f : 0.f; |
| 279 if (target_alpha == alpha_) { | 373 if (target_alpha == alpha_) { |
| 280 EndFade(); | 374 EndFade(); |
| 281 return; | 375 return; |
| 282 } | 376 } |
| 283 | 377 |
| 284 fade_end_time_ = base::TimeTicks::Now() + | 378 fade_end_time_ = base::TimeTicks::Now() + |
| 285 base::TimeDelta::FromMillisecondsD( | 379 base::TimeDelta::FromMillisecondsD( |
| 286 kFadeDurationMs * std::abs(target_alpha - alpha_)); | 380 kFadeDurationMs * std::abs(target_alpha - alpha_)); |
| 287 fade_start_position_ = position_; | 381 fade_start_position_ = focus_bottom_; |
| 288 client_->SetNeedsAnimate(); | 382 client_->SetNeedsAnimate(); |
| 289 } | 383 } |
| 290 | 384 |
| 291 void TouchHandle::EndFade() { | 385 void TouchHandle::EndFade() { |
| 292 DCHECK(enabled_); | 386 DCHECK(enabled_); |
| 293 animate_deferred_fade_ = false; | 387 animate_deferred_fade_ = false; |
| 294 fade_end_time_ = base::TimeTicks(); | 388 fade_end_time_ = base::TimeTicks(); |
| 295 SetAlpha(is_visible_ ? 1.f : 0.f); | 389 SetAlpha(is_visible_ ? 1.f : 0.f); |
| 296 } | 390 } |
| 297 | 391 |
| 298 void TouchHandle::SetAlpha(float alpha) { | 392 void TouchHandle::SetAlpha(float alpha) { |
| 299 alpha = std::max(0.f, std::min(1.f, alpha)); | 393 alpha = std::max(0.f, std::min(1.f, alpha)); |
| 300 if (alpha_ == alpha) | 394 if (alpha_ == alpha) |
| 301 return; | 395 return; |
| 302 alpha_ = alpha; | 396 alpha_ = alpha; |
| 303 drawable_->SetAlpha(alpha); | 397 drawable_->SetAlpha(alpha); |
| 304 } | 398 } |
| 305 | 399 |
| 306 } // namespace ui | 400 } // namespace ui |
| OLD | NEW |