| 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..0fe3612eab31714ea616529d42ad28eb635c944d 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,23 @@ void TouchHandle::SetVisible(bool visible, AnimationStyle animation_style) {
|
| EndFade();
|
| }
|
|
|
| -void TouchHandle::SetPosition(const gfx::PointF& position) {
|
| +void TouchHandle::SetFocus(const gfx::PointF& top, const gfx::PointF& bottom) {
|
| DCHECK(enabled_);
|
| - if (position_ == position)
|
| + if (focus_top_ == top && focus_bottom_ == bottom)
|
| 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) {
|
| + DCHECK(enabled_);
|
| + if (viewport_rect_ == viewport_rect)
|
| + return;
|
| +
|
| + viewport_rect_ = viewport_rect;
|
| + SetUpdateLayoutRequired();
|
| }
|
|
|
| void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
|
| @@ -142,7 +155,7 @@ void TouchHandle::SetOrientation(TouchHandleOrientation orientation) {
|
| return;
|
|
|
| orientation_ = orientation;
|
| - drawable_->SetOrientation(orientation);
|
| + SetUpdateLayoutRequired();
|
| }
|
|
|
| bool TouchHandle::WillHandleTouchEvent(const MotionEvent& event) {
|
| @@ -170,7 +183,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 +230,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 +250,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 +337,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 +353,9 @@ void TouchHandle::EndDrag() {
|
| TouchHandleOrientation deferred_orientation = deferred_orientation_;
|
| deferred_orientation_ = TouchHandleOrientation::UNDEFINED;
|
| SetOrientation(deferred_orientation);
|
| + // Handle layout may be deferred while the handle is dragged.
|
| + SetUpdateLayoutRequired();
|
| + UpdateHandleLayout();
|
| }
|
|
|
| if (animate_deferred_fade_) {
|
| @@ -284,7 +380,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();
|
| }
|
|
|
| @@ -303,4 +399,10 @@ void TouchHandle::SetAlpha(float alpha) {
|
| drawable_->SetAlpha(alpha);
|
| }
|
|
|
| +void TouchHandle::SetUpdateLayoutRequired() {
|
| + // TODO(AviD): Make the layout call explicit to the caller by adding this in
|
| + // TouchHandleClient.
|
| + is_handle_layout_update_required_ = true;
|
| +}
|
| +
|
| } // namespace ui
|
|
|