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.
5 #include "content/browser/renderer_host/input/touch_handle.h"
13 // Maximum duration of a fade sequence.
14 const double kFadeDurationMs
= 200;
16 // Maximum amount of travel for a fade sequence. This avoids handle "ghosting"
17 // when the handle is moving rapidly while the fade is active.
18 const double kFadeDistanceSquared
= 20.f
* 20.f
;
20 // Avoid using an empty touch rect, as it may fail the intersection test event
21 // if it lies within the other rect's bounds.
22 const float kMinTouchMajorForHitTesting
= 1.f
;
24 // The maximum touch size to use when computing whether a touch point is
25 // targetting a touch handle. This is necessary for devices that misreport
26 // touch radii, preventing inappropriately largely touch sizes from completely
27 // breaking handle dragging behavior.
28 const float kMaxTouchMajorForHitTesting
= 36.f
;
32 // Responsible for rendering a selection or insertion handle for text editing.
33 TouchHandle::TouchHandle(TouchHandleClient
* client
,
34 TouchHandleOrientation orientation
)
35 : drawable_(client
->CreateDrawable()),
37 orientation_(orientation
),
38 deferred_orientation_(TOUCH_HANDLE_ORIENTATION_UNDEFINED
),
40 animate_deferred_fade_(false),
44 DCHECK_NE(orientation
, TOUCH_HANDLE_ORIENTATION_UNDEFINED
);
45 drawable_
->SetEnabled(enabled_
);
46 drawable_
->SetOrientation(orientation_
);
47 drawable_
->SetAlpha(alpha_
);
48 drawable_
->SetVisible(is_visible_
);
49 drawable_
->SetFocus(position_
);
52 TouchHandle::~TouchHandle() {
55 void TouchHandle::SetEnabled(bool enabled
) {
56 if (enabled_
== enabled
)
63 drawable_
->SetEnabled(enabled
);
66 void TouchHandle::SetVisible(bool visible
, AnimationStyle animation_style
) {
68 if (is_visible_
== visible
)
71 is_visible_
= visible
;
73 // Handle repositioning may have been deferred while previously invisible.
75 drawable_
->SetFocus(position_
);
77 bool animate
= animation_style
!= ANIMATION_NONE
;
79 animate_deferred_fade_
= animate
;
89 void TouchHandle::SetPosition(const gfx::PointF
& position
) {
91 if (position_
== position
)
94 // Suppress repositioning a handle while invisible or fading out to prevent it
95 // from "ghosting" outside the visible bounds. The position will be pushed to
96 // the drawable when the handle regains visibility (see |SetVisible()|).
98 drawable_
->SetFocus(position_
);
101 void TouchHandle::SetOrientation(TouchHandleOrientation orientation
) {
103 DCHECK_NE(orientation
, TOUCH_HANDLE_ORIENTATION_UNDEFINED
);
105 deferred_orientation_
= orientation
;
108 DCHECK_EQ(deferred_orientation_
, TOUCH_HANDLE_ORIENTATION_UNDEFINED
);
109 if (orientation_
== orientation
)
112 orientation_
= orientation
;
113 drawable_
->SetOrientation(orientation
);
116 bool TouchHandle::WillHandleTouchEvent(const ui::MotionEvent
& event
) {
120 if (!is_dragging_
&& event
.GetAction() != ui::MotionEvent::ACTION_DOWN
)
123 switch (event
.GetAction()) {
124 case ui::MotionEvent::ACTION_DOWN
: {
127 const float touch_size
= std::max(
128 kMinTouchMajorForHitTesting
,
129 std::min(kMaxTouchMajorForHitTesting
, event
.GetTouchMajor()));
130 const gfx::RectF
touch_rect(event
.GetX() - touch_size
* .5f
,
131 event
.GetY() - touch_size
* .5f
,
134 if (!drawable_
->IntersectsWith(touch_rect
))
136 touch_down_position_
= gfx::PointF(event
.GetX(), event
.GetY());
137 touch_to_focus_offset_
= position_
- touch_down_position_
;
138 touch_down_time_
= event
.GetEventTime();
142 case ui::MotionEvent::ACTION_MOVE
: {
143 gfx::PointF new_position
=
144 gfx::PointF(event
.GetX(), event
.GetY()) + touch_to_focus_offset_
;
145 client_
->OnHandleDragUpdate(*this, new_position
);
148 case ui::MotionEvent::ACTION_UP
: {
149 // TODO(jdduke): Use the platform touch slop distance and tap delay to
150 // properly detect a tap, crbug.com/394093.
151 base::TimeDelta delay
= event
.GetEventTime() - touch_down_time_
;
152 if (delay
< base::TimeDelta::FromMilliseconds(180))
153 client_
->OnHandleTapped(*this);
158 case ui::MotionEvent::ACTION_CANCEL
:
168 bool TouchHandle::Animate(base::TimeTicks frame_time
) {
169 if (fade_end_time_
== base::TimeTicks())
175 1.f
- (fade_end_time_
- frame_time
).InMillisecondsF() / kFadeDurationMs
;
177 (position_
- fade_start_position_
).LengthSquared() / kFadeDistanceSquared
;
178 float u
= std::max(time_u
, position_u
);
179 SetAlpha(is_visible_
? u
: 1.f
- u
);
189 void TouchHandle::BeginDrag() {
195 client_
->OnHandleDragBegin(*this);
198 void TouchHandle::EndDrag() {
203 is_dragging_
= false;
204 client_
->OnHandleDragEnd(*this);
206 if (deferred_orientation_
!= TOUCH_HANDLE_ORIENTATION_UNDEFINED
) {
207 TouchHandleOrientation deferred_orientation
= deferred_orientation_
;
208 deferred_orientation_
= TOUCH_HANDLE_ORIENTATION_UNDEFINED
;
209 SetOrientation(deferred_orientation
);
212 if (animate_deferred_fade_
) {
215 // As drawable visibility assignment is deferred while dragging, push the
216 // change by forcing fade completion.
221 void TouchHandle::BeginFade() {
223 DCHECK(!is_dragging_
);
224 animate_deferred_fade_
= false;
225 const float target_alpha
= is_visible_
? 1.f
: 0.f
;
226 if (target_alpha
== alpha_
) {
231 drawable_
->SetVisible(true);
232 fade_end_time_
= base::TimeTicks::Now() +
233 base::TimeDelta::FromMillisecondsD(
234 kFadeDurationMs
* std::abs(target_alpha
- alpha_
));
235 fade_start_position_
= position_
;
236 client_
->SetNeedsAnimate();
239 void TouchHandle::EndFade() {
241 animate_deferred_fade_
= false;
242 fade_end_time_
= base::TimeTicks();
243 SetAlpha(is_visible_
? 1.f
: 0.f
);
244 drawable_
->SetVisible(is_visible_
);
247 void TouchHandle::SetAlpha(float alpha
) {
248 alpha
= std::max(0.f
, std::min(1.f
, alpha
));
252 drawable_
->SetAlpha(alpha
);
255 } // namespace content