Chromium Code Reviews| Index: ui/touch_selection/touch_handle.cc |
| diff --git a/ui/touch_selection/touch_handle.cc b/ui/touch_selection/touch_handle.cc |
| index 1925a1a474f09d793b6a983a061a13c3246851f3..476b9900b0097d4153ab5d90ba5be3b884455827 100644 |
| --- a/ui/touch_selection/touch_handle.cc |
| +++ b/ui/touch_selection/touch_handle.cc |
| @@ -63,9 +63,11 @@ static std::ostream& operator<<(std::ostream& os, |
| // Responsible for rendering a selection or insertion handle for text editing. |
| TouchHandle::TouchHandle(TouchHandleClient* client, |
| - TouchHandleOrientation orientation) |
| + TouchHandleOrientation orientation, |
| + const gfx::RectF& viewport_rect) |
| : drawable_(client->CreateDrawable()), |
| client_(client), |
| + viewport_rect_(viewport_rect), |
| orientation_(orientation), |
| deferred_orientation_(TouchHandleOrientation::UNDEFINED), |
| alpha_(0.f), |
| @@ -73,12 +75,16 @@ TouchHandle::TouchHandle(TouchHandleClient* client, |
| enabled_(true), |
| is_visible_(false), |
| is_dragging_(false), |
| - is_drag_within_tap_region_(false) { |
| + is_drag_within_tap_region_(false), |
| + is_handle_layout_update_required_(false), |
| + mirror_vertical_(false), |
| + mirror_horizontal_(false) { |
| DCHECK_NE(orientation, TouchHandleOrientation::UNDEFINED); |
| drawable_->SetEnabled(enabled_); |
| - drawable_->SetOrientation(orientation_); |
| + drawable_->SetOrientation(orientation_, false, false); |
| + drawable_->SetOrigin(focus_bottom_); |
| drawable_->SetAlpha(alpha_); |
| - drawable_->SetFocus(position_); |
| + handle_horizontal_padding_ = drawable_->GetDrawableHorizontalPaddingRatio(); |
| } |
| TouchHandle::~TouchHandle() { |
| @@ -104,7 +110,7 @@ void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { |
| // Handle repositioning may have been deferred while previously invisible. |
| if (visible) |
| - drawable_->SetFocus(position_); |
| + SetUpdateLayoutRequired(); |
| bool animate = animation_style != ANIMATION_NONE; |
| if (is_dragging_) { |
| @@ -118,16 +124,21 @@ void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) { |
| EndFade(); |
| } |
| -void TouchHandle::SetPosition(const gfx::PointF& position) { |
| - DCHECK(enabled_); |
| - if (position_ == position) |
| +void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) { |
| + 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
|
| return; |
| - position_ = position; |
| - // Suppress repositioning a handle while invisible or fading out to prevent it |
| - // from "ghosting" outside the visible bounds. The position will be pushed to |
| - // the drawable when the handle regains visibility (see |SetVisible()|). |
| - if (is_visible_) |
| - drawable_->SetFocus(position_); |
| + |
| + focus_top_ = top; |
| + focus_bottom_ = bottom; |
| + SetUpdateLayoutRequired(); |
| +} |
| + |
| +void TouchHandle::SetViewportRect(const gfx::RectF& viewport_rect) { |
| + if (viewport_rect_ == viewport_rect) |
| + return; |
| + |
| + viewport_rect_ = viewport_rect; |
| + SetUpdateLayoutRequired(); |
| } |
| void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { |
| @@ -142,7 +153,7 @@ void TouchHandle::SetOrientation(TouchHandleOrientation orientation) { |
| return; |
| orientation_ = orientation; |
| - drawable_->SetOrientation(orientation); |
| + SetUpdateLayoutRequired(); |
| } |
| bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { |
| @@ -170,7 +181,7 @@ bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) { |
| return false; |
| } |
| touch_down_position_ = touch_point; |
| - touch_drag_offset_ = position_ - touch_down_position_; |
| + touch_drag_offset_ = focus_bottom_ - touch_down_position_; |
| touch_down_time_ = event.GetEventTime(); |
| BeginDrag(); |
| } break; |
| @@ -217,8 +228,8 @@ bool TouchHandle::Animate(base::TimeTicks frame_time) { |
| float time_u = |
| 1.f - (fade_end_time_ - frame_time).InMillisecondsF() / kFadeDurationMs; |
| - float position_u = |
| - (position_ - fade_start_position_).LengthSquared() / kFadeDistanceSquared; |
| + float position_u = (focus_bottom_ - fade_start_position_).LengthSquared() / |
| + kFadeDistanceSquared; |
| float u = std::max(time_u, position_u); |
| SetAlpha(is_visible_ ? u : 1.f - u); |
| @@ -237,6 +248,86 @@ gfx::RectF TouchHandle::GetVisibleBounds() const { |
| return drawable_->GetVisibleBounds(); |
| } |
| +void TouchHandle::UpdateHandleLayout() { |
| + // Suppress repositioning a handle while invisible or fading out to prevent it |
| + // from "ghosting" outside the visible bounds. The position will be pushed to |
| + // the drawable when the handle regains visibility (see |SetVisible()|). |
| + if (!is_visible_ || !is_handle_layout_update_required_) |
| + return; |
| + |
| + is_handle_layout_update_required_ = false; |
| + |
| + // Update mirror values only when dragging has stopped to prevent unwanted |
| + // inversion while dragging of handles. |
| + if (client_->IsAdaptiveHandleOrientationEnabled() && !is_dragging_) { |
| + gfx::RectF handle_bounds = drawable_->GetVisibleBounds(); |
| + bool mirror_horizontal = false; |
| + bool mirror_vertical = false; |
| + |
| + const float handle_width = |
| + handle_bounds.width() * (1.0 - handle_horizontal_padding_); |
| + const float handle_height = handle_bounds.height(); |
| + |
| + const float bottom_y_unmirrored = |
| + focus_bottom_.y() + handle_height + viewport_rect_.y(); |
| + const float top_y_mirrored = |
| + focus_top_.y() - handle_height + viewport_rect_.y(); |
| + |
| + // In case the viewport height is small, like webview, avoid inversion. |
| + if (bottom_y_unmirrored > viewport_rect_.bottom() && |
| + top_y_mirrored > viewport_rect_.y()) { |
| + mirror_vertical = true; |
| + } |
| + |
| + if (orientation_ == TouchHandleOrientation::LEFT && |
| + focus_bottom_.x() - handle_width < viewport_rect_.x()) { |
| + mirror_horizontal = true; |
| + } else if (orientation_ == TouchHandleOrientation::RIGHT && |
| + focus_bottom_.x() + handle_width > viewport_rect_.right()) { |
| + mirror_horizontal = true; |
| + } |
| + |
| + mirror_horizontal_ = mirror_horizontal; |
| + mirror_vertical_ = mirror_vertical; |
| + } |
| + |
| + drawable_->SetOrientation(orientation_, mirror_vertical_, mirror_horizontal_); |
| + drawable_->SetOrigin(ComputeHandleOrigin()); |
| +} |
| + |
| +gfx::PointF TouchHandle::ComputeHandleOrigin() const { |
| + gfx::PointF focus = mirror_vertical_ ? focus_top_ : focus_bottom_; |
| + gfx::RectF drawable_bounds = drawable_->GetVisibleBounds(); |
| + float drawable_width = drawable_->GetVisibleBounds().width(); |
| + |
| + // Calculate the focal offsets from origin for the handle drawable |
| + // based on the orientation. |
| + int focal_offset_x = 0; |
| + int focal_offset_y = mirror_vertical_ ? drawable_bounds.height() : 0; |
| + switch (orientation_) { |
| + case ui::TouchHandleOrientation::LEFT: |
| + focal_offset_x = |
| + mirror_horizontal_ |
| + ? drawable_width * handle_horizontal_padding_ |
| + : drawable_width * (1.0f - handle_horizontal_padding_); |
| + break; |
| + case ui::TouchHandleOrientation::RIGHT: |
| + focal_offset_x = |
| + mirror_horizontal_ |
| + ? drawable_width * (1.0f - handle_horizontal_padding_) |
| + : drawable_width * handle_horizontal_padding_; |
| + break; |
| + case ui::TouchHandleOrientation::CENTER: |
| + focal_offset_x = drawable_width * 0.5f; |
| + break; |
| + case ui::TouchHandleOrientation::UNDEFINED: |
| + NOTREACHED() << "Invalid touch handle orientation."; |
| + break; |
| + }; |
| + |
| + return focus - gfx::Vector2dF(focal_offset_x, focal_offset_y); |
| +} |
| + |
| void TouchHandle::BeginDrag() { |
| DCHECK(enabled_); |
| if (is_dragging_) |
| @@ -244,7 +335,7 @@ void TouchHandle::BeginDrag() { |
| EndFade(); |
| is_dragging_ = true; |
| is_drag_within_tap_region_ = true; |
| - client_->OnDragBegin(*this, position()); |
| + client_->OnDragBegin(*this, focus_bottom()); |
| } |
| void TouchHandle::EndDrag() { |
| @@ -260,6 +351,9 @@ void TouchHandle::EndDrag() { |
| TouchHandleOrientation deferred_orientation = deferred_orientation_; |
| deferred_orientation_ = TouchHandleOrientation::UNDEFINED; |
| SetOrientation(deferred_orientation); |
| + // 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.
|
| + SetUpdateLayoutRequired(); |
| + UpdateHandleLayout(); |
| } |
| if (animate_deferred_fade_) { |
| @@ -284,7 +378,7 @@ void TouchHandle::BeginFade() { |
| fade_end_time_ = base::TimeTicks::Now() + |
| base::TimeDelta::FromMillisecondsD( |
| kFadeDurationMs * std::abs(target_alpha - alpha_)); |
| - fade_start_position_ = position_; |
| + fade_start_position_ = focus_bottom_; |
| client_->SetNeedsAnimate(); |
| } |